A Tour of jabber.xml

Now we know what patterns to look out for, we're well prepared to dive into a jabber.xml configuration file. As an example, we'll take one that's very similar to the default jabber.xml installed with version 1.4.1 of Jabber, but we'll plug in some extra components: the Conferencing component and a local JUD component.

The entire configuration content, with comment lines dividing up each section, can be found in Appendix A. It's definitely worth turning briefly to have a look at the XML before continuing, to get a feel for how the configuration is laid out.

In order to deal with it without going crazy, let's break down the XML into manageable chunks. We'll build configuration diagrams for each of the top-level tags that are children of the root tag <jabber/>. The opening tags for each of these chunks are as follows:

Most of these should be recognisable by now, but there are two chunks that we haven't come across yet: <io> and <pidfile>. These aren't components but nevertheless are part of the configuration for jabberd; there are also the two Logging component instances that we have not paid much attention to until now.

Figure 4-4 provides an overview of how the Jabber server is configured. It represents the contents of the jabber.xml configuration file in Appendix A in diagram form.

Figure 4-4. Configuration file in diagram form


+----------+                         +-----+
| sessions |                         | xdb |
+----------+-------------------+     +-----+------------------------+
|                      service |     |                          xdb | 
|--> host    yak               |     |--> host    *                 |
|--> load    jsm.so            |     |--> load    xdb_file.so       |
|--> config  filter, vCard,    |     |--> config  spool             |
|            register, welcome |     +------------------------------+
|            ...               |
+------------------------------+     +---------+
                                     | elogger |
+-----+                              +---------+--------------------+
| c2s |                              |                          log |
+-----+------------------------+     |--> host    *                 |
|                      service |     |--> logtype *                 |
|--> host    (c2s)             |     |--> format  ...               |
|--> load    pth_client.so     |     |--> file    ...               |
|--> config  authtime, ip,     |     |--> stderr                    |
|            karma             |     +------------------------------+
+------------------------------+
                                     +---------+
+-------+                            | rlogger |
| dnsrv |                            +---------+--------------------+
+-------+----------------------+     |                          log |
|                      service |     |--> host    *                 |
|--> host    *                 |     |--> logtype record            |
|--> load    dnsrv.so          |     |--> format  ...               |
|--> config  resend            |     |--> file    ...               |
+------------------------------+     +------------------------------+

+------+                             +-----+
| conf |                             | s2s |
+------+-----------------------+     +-----+------------------------+
|                      service |     |                      service |
|--> host    conference.yak    |     |--> host    (s2s)             |
|--> load    conference.so     |     |--> load    dialback.so       |
|--> config  public, vCard,    |     |--> config  legacy, ip, karma |
|            history, notice   |     +------------------------------+
|            room              |
+------------------------------+     +----+
                                     | io |
+-----+                              +----+--------------+
| jud |                              |--> rate   ...     |
+-----+------------------------+     |--> karma  ...     |
|                      service |     |--> ssl    ...     |
|--> host    jud.yak           |     |--> allow  ...     |
|--> load    jud.so            |     |--> deny   ...     |
|--> config  vCard             |     +-------------------+
+------------------------------+
                                     +---------+
                                     | pidfile |
                                     +---------+---------+
                                     |--> jabber.pid     |
                                     +-------------------+


We can see that the bulk of the Jabber server functionality described here is in the form of components. Let's take each of these components one by one and have a closer look.

Component instance: sessions

The sessions component, described by the configuration XML shown in Example 4-8 and shown in diagram form in Figure 4-5, provides Session Management features for users (the word "users" is employed in the widest possible sense—a user could be a person or a script) connecting with Jabber clients - through XML streams identified with the jabber:client stream namespace.

Figure 4-5. Diagram view of sessions component instance

+----------+                      
| sessions |                     
+----------+-------------------+ 
|                      service |
|--> host    yak               |  
|--> load    jsm.so            | 
|--> config  filter, vCard,    | 
|            register, welcome | 
|            ...               |
+------------------------------+ 

It also provides the services that give Jabber its IM capabilities— services such as roster management, message filtering, store-and-forward ("offline") message handling, and so on. These IM services are loaded individually as part of the component connection phase.

Example 4-8. jabber.xml configuration for the sessions component instance

<service id="sessions">

  <host><jabberd:cmdline flag="h">yak</jabberd:cmdline></host>

  <jsm xmlns="jabber:config:jsm">
    <filter>
        <default/>
        <max_size>100</max_size>
        <allow>
            <conditions>
                <ns/>
                <unavailable/>
                <from/>
                <resource/>
                <subject/>
                <body/>
                <show/>
                <type/>
                <roster/>
                <group/>
            </conditions>
            <actions>
                <error/>
                <offline/>
                <forward/>
                <reply/>
                <continue/>
                <settype/>
            </actions>
        </allow>
    </filter>
    <vCard>
      <FN>Jabber Server on yak</FN>
      <DESC>A Jabber Server!</DESC>
      <URL>http://yak/</URL>
    </vCard>
    <register notify="yes">
      <instructions>Choose a userid and password to register.</instructions>
      <name/>
      <email/>
    </register>
    <welcome>
      <subject>Welcome!</subject>
      <body>Welcome to the Jabber server on yak</body>
    </welcome>
    <!--
    <admin>
      <read>support@yak</read>
      <write>admin@yak</write>
      <reply>
        <subject>Auto Reply</subject>
        <body>This is a special administrative address.</body>
      </reply>
    </admin>
    -->
    <update><jabberd:cmdline flag="h">yak</jabberd:cmdline></update>
    <vcard2jud/>
    <browse>
      <service type="jud" jid="jud.yak" name="yak User Directory">
        <ns>jabber:iq:search</ns>
        <ns>jabber:iq:register</ns>
      </service>
      <conference type="public" jid="conference.yak" name="yak Conferencing"/>
    </browse>

  </jsm>

  <load main="jsm">
    <jsm>./jsm/jsm.so</jsm>
    <mod_echo>./jsm/jsm.so</mod_echo>
    <mod_roster>./jsm/jsm.so</mod_roster>
    <mod_time>./jsm/jsm.so</mod_time>
    <mod_vcard>./jsm/jsm.so</mod_vcard>
    <mod_last>./jsm/jsm.so</mod_last>
    <mod_version>./jsm/jsm.so</mod_version>
    <mod_announce>./jsm/jsm.so</mod_announce>
    <mod_agents>./jsm/jsm.so</mod_agents>
    <mod_browse>./jsm/jsm.so</mod_browse>
    <mod_admin>./jsm/jsm.so</mod_admin>
    <mod_filter>./jsm/jsm.so</mod_filter>
    <mod_offline>./jsm/jsm.so</mod_offline>
    <mod_presence>./jsm/jsm.so</mod_presence>
    <mod_auth_plain>./jsm/jsm.so</mod_auth_plain>
    <mod_auth_digest>./jsm/jsm.so</mod_auth_digest>
    <mod_auth_0k>./jsm/jsm.so</mod_auth_0k>
    <mod_log>./jsm/jsm.so</mod_log>
    <mod_register>./jsm/jsm.so</mod_register>
    <mod_xml>./jsm/jsm.so</mod_xml>
  </load>

</service>

Component type and identification

The opening tag:

<service id="sessions">

identifies this component instance to the backbone as a service type component and gives it a name ("sessions") that can be used for internal addressing and to distinguish it from other component instances.

Host filter

Assuming that our hostname isn't "sessions," it's just as well that we have a <host/> specification in this component instance description:

<host><jabberd:cmdline flag="h">yak</jabberd:cmdline></host>

which means that this session management component instance will handle packets addressed to the host "yak." [1] The <jabberd:cmdline flag="h"> ... </jabberd:cmdline> wrapper around the hostname means that this value ("yak") can be overridden by specifying a switch -h <hostname> when jabberd is invoked, as is described in Chapter 3. If you're sure you'll never want to override the hostname setting here, this <jabberd:cmdline/> wrapper can safely be removed from the configuration, to leave:

<host>yak</host>

As described earlier, you can specify more than one hostname - use a <host>...</host> pair for each one. This will effectively give you a virtual server effect where Jabber will respond to different hostnames. This is useful in situations such as deployment in an ISP where a single host serves multiple domains. The client data stored on the server (such as rosters, offline messages, and so on) is stored by the xdb component by hostname, so that a separate directory in the spool area will be used for each specified hostname.

For example, if you specified the two hosts:

<host>a-domain.com</host>
<host>b-domain.com</host>

then the data for two users jim@a-domain.com and john@b-domain.com would be stored as shown in Figure 4-6.

Figure 4-6. Storage of server-side user data by hostname

                        +--------+
                        | Jabber |
  jim@a-domain.com ---> | Server |
                        |        |
 john@b-domain.com ---> |        |
                        |        |          +-- a-domain.com/ -- jim.xml
                        +--------+          |
                               |            |
                               +-- spool/ --+
                                            |
                                            +-- b-domain.com/ -- john.xml

Although specifying multiple hostnames for the session management component instance will effect a sort of virtual hosting, with separate data storage as described, the rest of the features of the component will be identical. For example, this means that the list of available services that the client can request—the agent list (old terminology) or browse list (new terminology)—and the session features such as roster management, administration functions, private data storage and so on, will be identical. If you want to offer different services for different hostnames from the same Jabber server, see the section called Managing the Configuration later in this chapter.

Hostname needed here

You cannot use the catchall empty <host/> tag for the session management component—it needs to be given an explicit host identity in order to function.

Custom configuration

In the section called A typical component instance description earlier, we described the elements in this order: component type, component identification, host filter, connection method, custom configuration. Being XML, the configuration format is flexible enough to allow us to manage the ordering (but not the nesting!) of the configuration directives to suit our own layout purposes. In this instance, we come to the custom configuration—the connection method comes afterwards.

The sessions component (i.e. the JSM) offers a lot of facilities, which means that in order to attach an instance of the JSM into our Jabber server we have a lot of configuring to do.

Our configuration wrapper tag for the JSM instance is

<jsm xmlns="jabber:config:jsm">

The tag name "jsm" is simply representative of what the configuration pertains to; Once loaded, the JSM component will look for the configuration by the namespace identifier jabber:config:jsm. Within the wrapper tag we have different sections that approximately relate to the different services that the jsm is going to provide.

Filter Service

The message filter service, provided by the mod_filter module allows clients to set up mechanisms that can control and manage incoming messages as they arrive at the recipient's Jabber server—before they start on the final leg of the journey to the recipient's client.

The service allows each user to maintain their own filter, which is a collection of rules. A rule is a combination of conditions and actions. For each incoming message, the message filter service kicks in and goes through the rules contained in the message recipient's filter one by one, checking the characteristics of the incoming message using the conditions defined in each rule. If one of the conditions matches, then the action or actions defined in that rule are carried out and the message filter service stops going through the rules—unless the action specified is 'continue'—in which case the service goes on to the next rule. The 'continue' action makes it possible to chain together a complex series of checks and actions.

Figure 4-7. A message filter


   +-----------------------------------------+
   | filter                                  |
   | +-------------------------------------+ |
   | | rule                                | |
   | |   +-----------+       +-----------+ | |
   | | +-----------+ |     +-----------+ | | |
   | | | condition | | --> | action    | | | |
   | | |           | +     |           | + | |
   | | +-----------+       +-----------+   | |
   | +-------------------------------------+ |
   |                                         |
   | +-------------------------------------+ |
   | | rule                                | |
   | |   +-----------+       +-----------+ | |
   | | +-----------+ |     +-----------+ | | |
   | | | condition | | --> | action    | | | |
   | | |           | +     |           | + | |
   | | +-----------+       +-----------+   | |
   | +-------------------------------------+ |
   |                                         |
   | ...                                     |
   |                                         |
   +-----------------------------------------+

Each user's filter is stored on the server using the xdb component (see later). What does a typical filter look like? Well, Example 4-9 shows a filter that contains two rules -

  • Rule "holiday" checks the message recipient's presence and sends a 'holiday' notice back if the presence is set to 'Extended Away', and forwards the incoming message to a colleague.

  • Rule "custreply" checks to see if the message is from someone that exists in certain groups in the recipient's roster and if so sends an auto-reply to that person, sets the incoming message type to 'normal' (in case it was a 'chat' message), and allows the message to reach its original intended destination.

    This could be useful in a customer support scenario where the support representative could handle incoming queries in a queue of 'normal' messages but have an auto-reply sent out for each query telling the customer that their request will be dealt with shortly.

Example 4-9. A message filter with two rules

<query xmlns="jabber:iq:filter">
  <rule name="holiday">
    <show>xa</show>
    <reply>I'm on holiday - back on the 25th!</reply>
    <forward>mycolleague@yak</forward>
  </rule>
  <rule name="custreply">
    <group>CustomersNorth</group>
    <group>CustomersSouth</group>
    <reply>Thanks - an operator will attend to you shortly</reply>
    <continue/>
  </rule>
</query>

Note that there is no nesting or grouping to distinguish conditions from actions. In the first rule - "holiday" - there is one condition ( <show/> ) and two actions ( <reply/> and <forward/> ) and in the second rule - "custreply" - there are two conditions (two <group/>s) and two actions ( <reply/> and <continue/> ).

There are a few things to note from this example:

The <continue/> action means that the filter checking will move on to the 'next rule' which doesn't exist, meaning that the original message will still be delivered. No <continue/> would have meant that the message would have been dropped (that is, it wouldn't have reached it's final original destination) - because when a rule matches the actions in that rule are carried out and a successful delivery is implied.

The conditions are ORed together, that is to say if any of the conditions in a rule match then the rule has matched and all of actions defined in the rule are carried out.

So with this in mind, let's examine the message filter service configuration:

<filter>
    <default/>
    <max_size>100</max_size>
    <allow>
        <conditions>
            <ns/>
            <unavailable/>
            <from/>
            <resource/>
            <subject/>
            <body/>
            <show/>
            <type/>
            <roster/>
            <group/>
        </conditions>
        <actions>
            <error/>
            <offline/>
            <forward/>
            <reply/>
            <continue/>
            <settype/>
        </actions>
    </allow>
</filter>

Within the <filter/> configuration wrapper, we have three children:

<default/>

The <default/> tag allows the server administrator to specify default filter rules that will be applied for every user registered on that Jabber server. Specifying something like this:

<default>
  <rule name="server wide rule">
    <from>spammer@spamcity.com</from>
    <error>No spam please, we're British!</error>
  </rule>
</default>

will effectively filter out all messages from our friendly spammer.

The rules specified in the <default/> tag will be appended to any personal rules the user may have defined himself. This is important when you consider the order in which the rules are tested, and that once a rule is matched, filter processing stops (unless the <continue/> action is used).

<maxsize/>

Filter rule matching is expensive. We don't want to allow the user to go overboard with filter rules - we can place an upper limit on the number of rules in a filter with the <maxsize/> tag. (The default is rather large - anyone who can be bothered to create 100 rules deserves to have them all checked, in my opinion!)

<allow/>

The <allow/> tag specifies the <conditions/> and <actions/> that a user is allowed to use in building rules. Table 4-1 and Table 4-2 show the possible filter conditions and actions.

Table 4-1. Filter conditions

ConditionExampleDescription
<ns/><ns>jabber:iq:version</ns>Matches the namespace ('ns') of an <iq/> packet. [a]
<unavailable/><unavailable/>Matches when the recipient's presence type is 'unavailable'.
<from/><from>spammer@spamcity.com</from>Matches the sender's Jabber ID (JID) - user@host.
<resource/><resource>Work</resource>Matches the recipient's resource.
<subject/><subject>Work(!)</subject>Matches the message's subject (in the <subject/> tag) - must match exactly.
<body/><body>Are you there?</body>Matches the message content (in the <body/> tag) - must match exactly.
<show/><show>dnd</show>Matches the recipient's presence 'show' - usually one of normal (the default), chat, away, xa (eXtended Away) or dnd (Do Not Disturb).
<type/><type>chat</type>Matches the type of the incoming message (in the type="" attribute) - could be one of normal, chat, headline or error.
<roster/><roster/>Matches if the sender is in the recipient's roster.
<group/><group>Friends</group>Matches if the sender is in a particular group in the recipient's roster.
Notes:
a. The name "message filter service" is slightly inaccurate as incoming <iq/> (Info/Query) packets can also be filtered - and the matching takes place on the namespace described in the xmlns="" attribute.

Table 4-2. Filter actions

ActionExampleDescription
<error/><error>Address defunct</error>Sends an error reply to the sender.
<offline/><offline/>Stores the incoming message offline. The recipient will receive it the next time he logs on.
<forward/><forward>colleague@server</forward>The message will be forwarded to another Jabber ID (JID).
<reply/><reply>Be right back!</reply>A reply will be sent to the sender.
<settype/><settype>normal</settype>Changes the type of the incoming message (see <type/> in the Conditions table above).
<continue/><continue/>Special action to continue on to the next rule.

Server vCard

Every user can maintain a virtual business card - a vCard - which is stored server-side. vCards can be retrieved at any time by any user. The <vCard/> tag here in the jsm configuration gives the Jabber server an identity - its vCard can be retrieved also.

You can maintain the server's vCard data in this part of the jsm configuration:

<vCard>
  <FN>Jabber Server on yak</FN>
  <DESC>A Jabber Server!</DESC>
  <URL>http://yak/</URL>
</vCard>

All the vCard elements can be used for this vCard configuration, not just the ones shown here.

Registration Instructions

Registration instructions such as those defined here:

<register notify="yes">
  <instructions>Choose a userid and password to register.</instructions>
  <name/>
  <email/>
</register>

are available to whoever asks for them; in its most formal state, the procedure for creating a new user account on a Jabber server includes a first step of asking the server what is required for the registration process.

The registration service is provided by the mod_register module.

In reply to such a request (which is made with an <iq/> get request in the jabber:iq:register namespace - see Part II for details) the instructions and a list of required fields are returned by mod_register. Note that the list of fields provided in this <register/> section are over and above the standard required fields required in any case for registration:

  • <username/>

  • <password/>

so that in this particular configuration case both <name/> and <email/> and <username/> and <password/> will be sent in the reply. The text inside the <instructions/> tag is intended for display by the client if it supports such a dynamic process. Typically the client would request the registration requirements and build a screen asking the user to enter values for the required fields, while displaying the instructions received.

The notify="yes" attribute of the <register/> tag will cause a message to be automatically created and sent to the server administrator address(es) for every new account created. See the section called Administration for details about specifying administration addresses.

If you want to prevent registration of new accounts on your Jabber server, comment out this <register/> section. mod_register, the only standard module that handles <iq/> packets in the jabber:iq:register namespace, will refuse to handle register requests if there is no <register/> section in the configuration, and so a "Not Implemented" reply will be sent to the registration details request.

Welcome Message

The welcome message defined here:

<welcome>
  <subject>Welcome!</subject>
  <body>Welcome to the Jabber server on yak</body>
</welcome>

will be sent to all new users the first time they log on. The <subject/> and <body/> contents are simply placed in a normal <message/> and sent off to the new Jabber ID (JID).

Administration

While the Unix user acts as the overall administrator for the Jabber server (for starting and stopping jabberd, for example) it is possible to specify administration rights for certain Jabber users that are local to the server. 'Local' means users that are defined as belonging to the host (or hosts) specified in the <host/> tag within the same jsm component instance definition - if the host tag is

<host>server.com</host>

then the JIDs dj@server.com and admin@server.com are local, but admin@anotherserver.com is not.

The only difference between an administration JID and a 'normal' JID is that the former is specified in tags in this section and the latter isn't. When a JID is specified between either the <read/> or <write/> tags, then it can be used to perform 'administrative' tasks.

The <admin/> section as delivered in the standard jabber.xml that comes with version 1.4.1 (see Appendix A) is commented out. Make sure that you remove the comment lines to activate the section if you want to make use of the administrative features:

<admin>
  <read>support@yak</read>
  <write>admin@yak</write>
  <reply>
    <subject>Auto Reply</subject>
    <body>This is a special administrative address.</body>
  </reply>
</admin>

If you want to specify more than one JID with administrative rights, simply repeat the tags, like this:

<read>admin1@yak</read>
<read>admin2@yak</read>
<read>admin3@yak</read>

Placing a JID inside of a <write/> tag implies that that JID also has <read/> administration rights. So there's not much point in doing something like this:

<read>admin@yak</read>
<write>admin@yak</write>

So what are the administrative features available to JIDs placed inside the <read/> and <write/> tags?

Administrative Features for <read/> JIDs

For JIDs appearing in a <read/> tag in the <admin/> section, these are the features available:

  • Retrieve list of users currently online

    By sending one of two possible types of query to the server, a JID can retrieve a list of users that currently have a session on the (local) Jabber server. The results come in one of two forms, depending on the query type. The first query version is of the 'legacy' iq:admin type and the second is of the newer iq:browse type.

    The list of users in both sorts of results contain the user JID, for how long the user has been logged on (measured in seconds), how many packets have been sent from the user's session, and how many packets have been send to the user's session. The first query version also contains presence information for each user in the list.

  • Receipt of 'administrative queries'

    Users normally send messages to other users - to other JIDs, where a JID is composed of a username and a hostname (a Jabber servername). The Jabber server itself is also a valid recipient, and the 'JID' in this case is just the servername itself - no username and no @ sign. [2]

    If a user sends a message to the server, it will be forwarded to the JIDs listed in the <read/> (and <write/>) tags in this <admin/> section, and the reply defined in the <reply/> tag will be sent back to the user as an automated response.

For JIDs appearing in a <write/> tag in the <admin/> section, these are the features available:

  • Same as <read/>

    JIDs listed in <write/> tags automatically have access to the same features as those JIDs listed in <read/> tags.

  • Configuration retrieval

    In a similar way to how a list of online users can be requested by sending a query of the iq:admin variety, a copy of the jsm configuration can be requested by sending an iq:admin query to the server. The difference is that in the former user list request, a request tag <who/> is sent inside the query, and in this configuration request, a <config/> tag is sent.

    The configuration XML, as it is defined in the jsm component instance section of the Jabber server being queried, is returned as a result.

  • Sending administrative messages

    Two types of administrative messages can be sent - an announcement to all online users, and a 'message of the day' (MOTD). The announcement goes out to all users currently online. Similarly, the MOTD goes out to all users, but not only those online - when someone logs on and starts a session the MOTD will be sent to them too, unlike the announcement, which will 'expire' as soon as it is sent. The MOTD will not expire, unless explicitly made to do so. The MOTD can also be updated - those that had already received the MOTD won't receive the updated copy during their current session, but anyone logging on after the update will receive the new version of the message.

Update Info Request

The mod_version module provides a simple service that, at server startup, queries a central repository of Jabber software version information at update.jabber.org. The <update/> configuration tag:

<update><jabberd:cmdline flag="h">yak</jabberd:cmdline></update>

is used to control this query.

If the <update/> tag is present, the query is sent. If the update tag is not present, the query is not sent.

If you do intend leaving the <update/> tag in, you need to make sure

  1. the hostname specified as the value in the tag is resolvable and reachable as this is your Jabber server address to which the central repository will try to send back information (if there happens to be a newer version of the server software - specifically the jsm component - available)

  2. your Jabber server is connected to the Internet to be able to reach update.jabber.org. You also need to be running instances of the Hostname Resolution and Server (to Server) Connections components so that your Jabber server can resolve the update.jabber.org host and send the query out.

The jsm component version releases are fortunately not so frequent that you require an automated mechanism to keep up with what's new; also you may wish to run an internal Jabber server with no connection to the outside world. So it is not uncommon for this section to be commented out. The jsm will still function without this piece of configuration.

It is worth noting here, however, that Jabber clients also use the central repository to find out about newer versions of themselves. As all Jabber client communication goes through the server you need to realise that commenting out the <update/> tag will not stop clients sending their queries. [3]

Auto-Update of JUD

The Jabber User Directory (JUD) is a service that provides a directory service of user names and addresses. The service comes in the form of a component - we'll be looking at the component instance definition of a JUD later in this chapter. If a Jabber server is running a JUD service, then you can connect to it with your Jabber client and enter your name and address details and query it as you would any directory service to find details of other people.

At the same time, each user has the possibility of maintaining his own vCard - we discussed vCards earlier in the section called Server vCard. In the same way that the server's vCard can be requested and retrieved, you can request a user's vCard, and the user whose vCard is requested does not have to be connected at that moment for the request to be fulfilled - the vCards are stored server-side and the Jabber server handles the request (not the user's client).

So in many ways it makes sense to align the data in the user vCard with data stored in a JUD. The

<vcard2jud/>

configuration tag allows this alignment to happen automagically; if it appears in the configuration, it will cause any vCard updates (that would be typically performed by users changing their personal information via their Jabber clients) to be not only stored server-side in the vCard but also to be passed on to a JUD.

Which JUD? Well, the first one that's defined in the <browse/> section of the configuration, which is described next. Effectively it means that if you run a local JUD but also connect to the JUD running on jabber.org, you can choose which JUD will be the recipient of the vCard updates by placing that one before any others in the <browse/> list. [4]

If you're not running a JUD locally, or you simply don't want your users' vCard updates going to a JUD, you can safely comment this tag out.

Browsable Service Information

As the Jabber server administrators, we know what services are available on our Jabber server - what components are connected and what features they offer. We know for example that we're running a JUD locally, and have a Conferencing component.

But how do we let the Jabber clients know? If they're to be able to provide their users with an agreeable experience and expose them to all the server features available, we need some way to allow them to request information about what the server that they're connected to offers. Jabber has a powerful feature called 'browsing' which allows one entity to query another entity for information. Browsing defines a simple request/response exchange and with that provides a singular and uniform way to retrieve (on the requestors part) and expose (on the requestees part) feature information and availability.

Bearing that in mind, we can guess what the <browse/> section of the jsm custom configuration is for:

<browse>
  <service type="jud" jid="jud.yak" name="yak User Directory">
    <ns>jabber:iq:search</ns>
    <ns>jabber:iq:register</ns>
  </service>
  <conference type="public" jid="conference.yak" name="yak Conferencing"/>
</browse>

Each child of the <browse/> tag defines a feature - in this case a 'service' - that the Jabber server offers. Of course, these services are the ones over and above the services provided by the basic components such as Session Management, Hostname Resolution and so on.

So we have two services defined ('exposed') in the <browse/> configuration.

a local JUD:

<service type="jud" jid="jud.yak" name="yak User Directory">
  <ns>jabber:iq:search</ns>
  <ns>jabber:iq:register</ns>
</service>

and a conferencing service:

<conference type="public" jid="conference.yak" name="yak Conferencing"/>

The browsing features are covered in Part II, but briefly we can see here that each browsable 'item' is identified by a JID ( jid="jud.yak" and jid="conference.yak") and is classified using a category which is the combination of the item's outermost tag and the value of the tag's type attribute. So the JUD is classified as service/jud and has a JID of jud.yak, and the conferencing service is classified as conference/public and has a JID of conference.yak. The type="" and jid="" attributes are required. Each item has an optional name="" attribute for use when the item is displayed, for example.

Some services offer well-known facilities such as search and registration, which are commonly found across different services. These facilities can be described directly in the browse item, so that the entity requesting information about services receives information directly in the first request 'hit' as to what facilities are available for each service:

<ns>jabber:iq:search</ns>
<ns>jabber:iq:register</ns>

The 'ns' in the facility tagname (<ns/>) stands for namespace; it is via namespace-qualified requests to a service that features are utilised. In this case, the 'search' facility is represented by the jabber:iq:search namespace and the 'registration' facility is represented by the jabber:iq:register namespace.

Component Connection Method

Phew! Now that we've got the configuration out of the way, we can have a look how the jsm is loaded. And we can see immediately from the <load/> tags that it's connected using the library load method.

<load main="jsm">
  <jsm>./jsm/jsm.so</jsm>
  <mod_echo>./jsm/jsm.so</mod_echo>
  <mod_roster>./jsm/jsm.so</mod_roster>
  <mod_time>./jsm/jsm.so</mod_time>
  <mod_vcard>./jsm/jsm.so</mod_vcard>
  <mod_last>./jsm/jsm.so</mod_last>
  <mod_version>./jsm/jsm.so</mod_version>
  <mod_announce>./jsm/jsm.so</mod_announce>
  <mod_agents>./jsm/jsm.so</mod_agents>
  <mod_browse>./jsm/jsm.so</mod_browse>
  <mod_admin>./jsm/jsm.so</mod_admin>
  <mod_filter>./jsm/jsm.so</mod_filter>
  <mod_offline>./jsm/jsm.so</mod_offline>
  <mod_presence>./jsm/jsm.so</mod_presence>
  <mod_auth_plain>./jsm/jsm.so</mod_auth_plain>
  <mod_auth_digest>./jsm/jsm.so</mod_auth_digest>
  <mod_auth_0k>./jsm/jsm.so</mod_auth_0k>
  <mod_log>./jsm/jsm.so</mod_log>
  <mod_register>./jsm/jsm.so</mod_register>
  <mod_xml>./jsm/jsm.so</mod_xml>
</load>

It's clear that the more complex version of the method is employed here - as described in "Component Connection Methods" earlier in this Chapter - the jsm module itself is loaded through the <jsm>...</jsm> tag pair and this in turn pulls in the other modules that are specified with the mod_* module name tag pairs.

We've already become aquainted with some of the modules in this list; here's a quick summary of the ones that are being loaded here:

Modules loaded in jsm

mod_echo

This module provides a simple echo service that echoes back whatever you send it.

mod_roster

This module provides roster management services; the roster is stored server-side.

mod_time

You can request the server send you a timestamp local to the server - this is the module that handles this request.

mod_vcard

This is the module that handles requests for the Jabber server's vCard and also the user vCard management (such as submission to a JUD on change, and storing / retrieving the data from the server-side storage).

mod_last

The mod_last provides facilities for returning 'last logout' information for users, or in the case of a query on the server itself, server uptime.

mod_version

This is the module that provides the version query service described earlier in the section called Update Info Request.

mod_announce

The server-wide announcements and MOTD facilities available to Jabber server administrators are provided by this module.

mod_agents

The mod_agents module responds to requests for 'agent' information made to the server. This is the module that returns the information in the <browse/> tag in the jsm configuration. It can also return a summary of the server consisting of the server's vCard and whether new user registrations are open.

When returning <browse/> data, it gives similar information to mod_browse (see the next entry) and is provided for backwards compatibility. The agent information is requested with two namespaces, iq:agent (for information on the server) and iq:agents (for information on a list of 'agents' - the old name for 'services'); these namespaces are being 'retired' in deference to the new iq:browse namespace.

mod_browse

The mod_browse module responds to browsing requests made on the server or on users defined on that server. The module can also be used by users to modify the information returned if a browse request is made against them.

mod_admin

This module provides the administrative features described in the section called Administration. The module itself determines which JIDs are allowed access to which features (according to the configuration in the <admin/> block).

mod_filter

The services described in the section called Filter Service are provided by this module.

mod_offline

Being offline - which in this sense means not being connected to the Jabber server and having an (online) session - doesn't prevent a user receiving messages. They are merely stored offline and forwarded to him when he becomes available - when he logs on and starts a session. mod_offline provides these storage and forwarding services. [5]

mod_presence

The management of presence information - whether a user is online or offline, what his presence settings currently are, who should be sent the information, and so on - these facilities are provided by the mod_presence module.

mod_auth_*

Authentication must take place when a user connects to the Jabber server and wishes to start a session. There are currently three types of authentication supported by the Jabber server - the differentiation is in how the password exchange and comparison is managed:

  • plaintext. User passwords are stored in plaintext on the server and are transmitted from the client to the server in plaintext. [6] A simple comparison is made at the server to validate.

  • digest. User passwords are stored in plaintext on the server but no password is transmitted from the client to the server; instead, an SHA-1 digest is created by the client from the concatenation of the client's session id and the password and sent to the server, where the same digest operation is carried out and the results compared.

  • zero knowledge. No user passwords are stored on the server, nor transmitted from the client to the server. A combination of hash sequencing on the client side with a final hash and comparison on the server side allows credentials to be checked in a secure way.

There are three mod_auth_* modules - one for each of these authentication types.

mod_log

mod_log simply records the ending of each user session.

mod_register

The mod_register module provides the services to register (create a new user) and unregister (remove a user) with the server.

mod_xml

Storage and retrieval of private and shared data by users is made possible by this module.

Component instance: xdb

The xdb component, described by the configuration XML shown in Example 4-10 and shown in diagram form in Figure 4-8, provides data storage for the server - it is the XML DataBase.

Figure 4-8. Diagram view of xdb component instance

+-----+                      
| xdb |                     
+-----+------------------------+ 
|                          xdb |
|--> host    *                 |  
|--> load    xdb_file.so       | 
|--> config  spool             | 
+------------------------------+ 

All storage requirements by components connected to the Jabber backbone can be fulfilled by an xdb component. In normal configurations, there is a single instance, although it is possible to have more than one, each handling separate areas of storage, possibly using different storage mechanisms.

Example 4-10. jabber.xml configuration for the xdb component instance

<xdb id="xdb">

  <host/>

  <load>
    <xdb_file>./xdb_file/xdb_file.so</xdb_file>
  </load>

  <xdb_file xmlns="jabber:config:xdb_file">
    <spool><jabberd:cmdline flag='s'>./spool</jabberd:cmdline></spool>
  </xdb_file>

</xdb>

Component Type and Identification

The opening tag

<xdb id="xdb">

identifies this component instance to the backbone as an xdb type component, and gives it a name "xdb", in the same way that the sessions service has a name "sessions".

Host Filter

For the host filter, we have an empty tag

<host/>

specified, which signifies that this xdb component instance will answer data storage and retrieval requests for all hosts. This in turn means that all data to be stored server-side will be stored using the same data storage mechanism, in this case xdb_file, which is a simple 'lowest common denominator' storage system based upon directories containing files with XML content; these files are at a ratio of one per JID, plus a 'global' file where storage of data not tied to a JID is required. [7]

If you want to use separate data storage mechanisms for your different virtual servers, for example, you can define more than one xdb instance in your jabber.xml configuration and have the first use one storage system (say, xdb_file) and the second use another (say, an RDBMS-based system). [8]

You may also want to store data from different virtual hosts in different places on your system; by specifying more than one xdb instance, even if each of them uses the same storage mechanism, you can specify a different 'spool' directory in the configuration for each one.

As well as a host filter, there is another filter possible for xdb components. This is the namespace filter, represented by the <ns/> tag.

Every xdb storage and retrieval requests is made with a namespace definition; for example, to retrieve the last logoff time for a user, the mod_last module makes a data retrieval request of the xdb component and specifies the jabber:iq:last namespace in that request, and to check if a user is using the zero-knowledge authentication method, the mod_auth_0k module makes a data retrieval request and specifies the jabber:iq:auth:0k namespace.

If you want an xdb component instance to only handle requests qualified with certain namespaces, specify them with the <ns/> tag. Example 4-11 shows the initial part of an xdb component instance definition that is to handle jabber:iq:roster and jabber:iq:last qualified storage and retrieval request for the host a-domain.com.

Example 4-11. Host and namespace filters in an xdb definition

<xdb id="xdb">

  <host>a-domain.com</host>
  <ns>jabber:iq:roster</ns>
  <ns>jabber:iq:last</ns>
  
  ...

</xdb>

No namespace filter in an xdb component instance definition implies the instance is to handle requests qualified by any namespace - the equivalent of an empty tag:

<ns/>

To <ns/> or not to <ns/>

If you are going to use namespace filters for your xdb components, make sure you specify them for every xdb component instance definition, otherwise you will receive an error message to the effect that packet routing will be incorrect and your Jabber server will not start.

Custom Configuration

The custom configuration section in our xdb component instance definition is specific to the data storage mechanism that we're going to be using. In this case it's the xdb_file mechanism, and so we have the custom configuration wrapped by a tag qualified with a namespace to match:

<xdb_file xmlns="jabber:config:xdb_file">
  <spool><jabberd:cmdline flag='s'>./spool</jabberd:cmdline></spool>
</xdb_file>

Again, the tag name 'xdb_file' is unimportant - the part that must be correct is the namespace jabber:config:xdb_file.

The configuration describes a single setting - where the spool area is. This, in the context of our xdb_file mechanism, is the 'root' directory within which hostname-specific directories are created and used to store JID-specific and global XML data files. As the configuration stands here, the value (./spool) can be overridden at server startup time with the -s switch.

There is another configuration tag available for use here too. Using the configuration as it stands here, the xdb_file component would cache data indefinitely; if you were to modify data directly in the files in the spool area the modifications wouldn't have any effect for data that had already been retrieved for a JID in the course of a server's uptime. In other words, once data has been read from file, it is cached until the server is stopped. [9]

The <timeout/> configuration tag can be employed to control this cacheing. Used with a value that represents a number of seconds, the <timeout/> tag will force data in the cache to be purged (and therefore re-read from file the next time it's requested) after that number of seconds of lifetime. Table 4-3 shows the effects of various values on cacheing.

Table 4-3. Effect of <timeout/> tag

Tag valueExampleEffect
Less than 0<timeout>-1</timeout>No cache purge will be carried out and the cached data will live forever. This is the equivalent of having no explicit <timeout/> tag set.
0<timeout>0</timeout>Cache will be purged 'immediately'. This is the same as having no cache.
More than 0<timeout>120</timeout>Cached data will be purged after a certain lifetime specified (in seconds) as the value of the tag. In this example it's two minutes. Don't bother setting a positive value less than 30 - the cache purge check mechanism only runs every 30 seconds so any resolution beyond 30 is meaningless.

Component Connection Method

The component connection method is library load.

<load>
  <xdb_file>./xdb_file/xdb_file.so</xdb_file>
</load>

The shared library ./xdb_file/xdb_file.so is loaded and the xdb_file() function is called to initialise the component.

Component Instance: c2s

The c2s component, described by the configuration XML shown in Example 4-12 and shown in diagram form in Figure 4-9, provides the Client (to Server) Connections service—it manages Jabber client connections to the Jabber server.

Figure 4-9. Diagram view of c2s component instance

+-----+                      
| c2s |                     
+-----+------------------------+ 
|                      service |
|--> host    (c2s)             |  
|--> load    pth_client.so     | 
|--> config  authtime, ip,     | 
|            karma             |
+------------------------------+ 

Example 4-12. jabber.xml configuration for the c2s component instance

<service id="c2s">

  <load>
    <pthsock_client>./pthsock/pthsock_client.so</pthsock_client>
  </load>

  <pthcsock xmlns='jabber:config:pth-csock'>
    <authtime/>
    <karma>
      <init>10</init>
      <max>10</max>
      <inc>1</inc>
      <dec>1</dec>
      <penalty>-6</penalty>
      <restore>10</restore>
    </karma>
    <ip port="5222"/>
  </pthcsock>

</service>

Component Type and Identification

The opening tag

<service id="c2s">

identifies this component instance to the backbone as a service type component, and gives it the name "c2s".

Host Filter

The c2s component has no explicit <host/> tag; the identification of the service with the id="" attribute is enough, and the value of the host filter will be taken as that identification. As long as the specified id is unique within the context of the whole configuration, the component will be able to function correctly. It is normally set to "c2s" by convention.

Custom Configuration

The custom configuration for our c2s component contains three main tags. The first, <authtime/> allows us to specify a time limit within which the connecting client has to have completed the authentication procedure. This includes sending the initial document stream identifier with the jabber:client namespace. Setting this to, say, ten seconds:

<authtime>10</authtime>

will allow the client up to 10 seconds to authenticate, after which c2s will drop the connection. Setting the time limit to 0 seconds, which can be accomplished with an empty tag:

<authtime/>

effectively gives the client an unlimited amount of time within which to authenticate.

The next tag we find in the c2s component instance configuration is <karma/>. This is a way of controlling bandwidth usage through the connections, and will be explained when we visit the "<io/> Section" later on in this Chapter.

Then we come to the <ip/> configuration tag.

<ip port="5222"/>

The default port for client connections is 5222. This is where it is specified. The <ip/> tag can contain an IP address - if you specify one like this:

<ip port="5222">192.168.0.4</ip>

then only socket connections will be made to that specific combination of port and IP address. Not specifying an IP address means that the c2s service will bind to the port on all (INADDR_ANY) IP addresses on the host.

You can specify more than one combination of port and IP address using multiple <ip/> tags:

<ip port="5222">
<ip port="5225">127.0.0.1</ip>

which here means client socket connections will be listened for on port 5222 on any IP address and port 5225 on the localhost address.

There are three other configuration tags not used here but worth identifying now.

<rate/>, like <karma/> is used to control connectivity and will be explained along with that tag in "<io/> Section" later.

<alias/> is a way of providing alias names for your Jabber server. When a Jabber client makes a connection, the opening gambit is the root of the XML document that is to be streamed over the connection:

<stream:stream to="furrybeast" xmlns="jabber:client"
               xmlns:stream="http://etherx.jabber.org/streams">

"furrybeast" may be a DNS alias for "yak", and is specified by the client here in the to="" attribute of the document's root tag (<stream/>).

With the <alias/> tag, we can 'fix' the incoming host specification by replacing it with what we as the server want it to be. If this document root tag were to be sent to our Jabber server configured as "yak" and we had an

<alias/> tag thus:

<alias to="yak">furrybeast</alias>

then the incoming host name specification "furrybeast" would be recognised and 'translated' to "yak" in the response:

<stream:stream xmlns:stream='http://etherx.jabber.org/streams'
               id='3AE71597' xmlns='jabber:client' from='yak'>

Rather than specify a hostname to translate, a default alias name can be specified like this:

<alias to="yak"/>

meaning that any connections to the c2s component would have their Jabber host name specification 'translated' to "yak" if necessary.

<ssl/> is the equivalent of the <ip/> tag and works in exactly the same way, with two exceptions:

  • an IP address must be specified (that means something like

    <ssl port="5223"/>

    is not allowed).

  • the connections are encrypted using SSL - for this the Jabber server must have been configured to use SSL - see Chapter 3 and the "io Section" later in this Chapter for details.

Component Connection Method

The component connection method is library load.

<load>
  <pthsock_client>./pthsock/pthsock_client.so</pthsock_client>
</load>

The shared library ./pthsock/pthsock_client.so is loaded and the pthsock_client() function is called to initialise the component.

Logging Definition: elogger

It has already been intimated that the log type components are exceptions to the general pattern when it comes to defining what they are in relation to the Jabber server. In fact, the logging 'components' aren't really separate components at all - they are part of the jabberd backbone. Nevertheless, it is still worthwhile referring to them as components as they can be defined with different characteristics, to perform different logging tasks.

Figure 4-10. Diagram view of elogger

+---------+                      
| elogger |                     
+---------+--------------------+ 
|                          log |
|--> host    *                 |  
|--> logtype *                 | 
|--> format  ...               | 
|--> file    ...               | 
|--> stderr                    | 
+------------------------------+ 

The configuration XML for elogger is shown in Example 4-13, and is represented in diagram form in Figure 4-10.

Example 4-13. jabber.xml configuration for elogger

<log id='elogger'>
  <host/>
  <logtype/>
  <format>%d: [%t] (%h): %s</format>
  <file>error.log</file>
  <stderr/>
</log>

Component Type and Identification

The opening tag clearly marks elogger as a log type component. The name given in the id="" attribute is "elogger".

Host Filter

elogger will record log records for any hosts according to the empty host filter tag specified here:

<host/>

Custom Configuration

Apart from the host filter declaration, every other tag within a <log/> definition can be regarded as configuration. Taking each tag in turn, we have:

  • <logtype/>

    This tag declares which types of logging record will be handled by this logging definition. [10]

    The tag can either be empty, or contain one of the following values: alert, notice, record or warn. You can specify more than one <logtype/> tag to capture more than one log type. If you specify an empty tag (as is the case with the elogger component here) then all log types will be captured and handled, apart from any log types that are explicitly declared elsewhere in other logging components. What does this mean? Well, in our case, since we have a second log type component "rlogger" (described in the next section) that has an explicit

    <logtype>record</logtype>

    this elogger component won't receive log records of type 'record' to handle.

  • <format/>

    A logging component will typically write out the data it receives in a human readable format. With the <format/> tag, we can specify how the data appears. There are four variables which we can embellish with whatever text we like to form something that will be meaningful to us (and perhaps easily parseable for our scripts). The four variables are shown in table 4-4.

    In elogger's <format/> tag, we have

    %d: [%t] (%h): %s
    so a typical log record written by elogger might look like this:
    20010420T21:38:30: [warn] (yak): dropping a packet to yak
      from jsm@update.jabber.org/1.4.1: Unable to deliver, destination unknown

  • <file/>

    Typically the output from a logging component goes to a file. You can specify the name of the file with the <file/> tag.

  • <stderr/>

    Additionally, it's possible to have the output from a logging component written to STDERR - place the empty <stderr/> tag in the logging component's definition to have this happen.

Table 4-4. Logging component variables for <format/>

VariableDescription
%dTimestamp
%hHost
%sThe actual log message
%tLog type

Logging Definition: rlogger

Logging definition elogger is a general catch-all component that serves to direct all unhandled log records to a log file error.log. The logging definition rlogger on the other hand has been defined specifically to capture and store (to a file—record.log) record type log records.

Figure 4-11. Diagram view of rlogger

+---------+                      
| rlogger |                     
+---------+--------------------+ 
|                          log |
|--> host    *                 |  
|--> logtype record            | 
|--> format  ...               | 
|--> file    ...               | 
+------------------------------+ 

The configuration XML for rlogger is shown in Example 4-14, and is represented in diagram form in Figure 4-11.

Example 4-14. jabber.xml configuration for rlogger

<log id='rlogger'>
  <host/>
  <logtype>record</logtype>
  <format>%d %h %s</format>
  <file>record.log</file>
</log>

Component Type and Identification

Like elogger, rlogger is identified as a log type component. It takes its name from the id="" attribute.

Host Filter

Again, like elogger, this logging definition will handle log records for any hosts.

Custom Configuration

The custom configuration of rlogger is very similar to that of elogger, except that the target file is called record.log (the <file/> tag), the output format is slightly different (the <format/> tag) and no output to STDERR is desired.

Component Instance: dnsrv

The dnsrv component, described by the configuration XML shown in Example 4-15 and shown in diagram form in Figure 4-12, provides routing logic and name resolution for packets that are destined for a non-local component; in other words for a component that is running on another Jabber server. [11]

Figure 4-12. Diagram view of dnsrv component instance

+-------+                      
| dnsrv |                    
+-------+----------------------+ 
|                      service |
|--> host    *                 |  
|--> load    dnsrv.so          | 
|--> config  resend            | 
+------------------------------+ 

Example 4-15. jabber.xml configuration for the dnsrv component instance

<service id="dnsrv">

  <host/>

  <load>
    <dnsrv>./dnsrv/dnsrv.so</dnsrv>
  </load>

  <dnsrv xmlns="jabber:config:dnsrv">
  	<resend service="_jabber._tcp">s2s</resend>
  	<resend>s2s</resend>
  </dnsrv>

</service>

The component, once started, forks to spawn a child process that services the actual resolution requests and the route determination. The component and its child communicate with a simple XML stream within which hostnames are passed to the child process in a 'query' tag:

<host>update.jabber.org</host>

and answers are passed back in the form of attribute additions to the original query tag:

<host ip='208.245.212.100' to='s2s'>update.jabber.org</host>

Component Type and Identification

The component is a service, and is identified with the name "dnsrv":

<service id="dnsrv">

Host Filter

The dnsrv is to provide hostname resolution and routing for all component activity within the Jabber server. For this reason, it needs to be open to all comers and has an empty host filter tag:

<host/>

Custom Configuration

The dnsrv component provides hostname lookup and dynamic routing services. To this end, the configuration concerns itself with defining how the routing is to be determined.

The configuration, identified with the jabberd:config:dnsrv namespace, contains a list of entries that describe service-types and next-delivery-point data. What does this mean? In hostname resolution, a lookup request can be made where a service and protocol are specified as well as a domain name. In the case where more than one server shares the same domain name, and services (such as Jabber) are managed across the servers, different host addresses can be returned, depending on the service requested. So far so good - this is our resolution part of the deal covered. But what happens once an IP address has been returned? The packet destined for the non-local component must be sent on its way - but via where? This is what the next-delivery-point data specifies.

If we examine the configuration, we see this:

<dnsrv xmlns="jabber:config:dnsrv">
  <resend service="_jabber._tcp">s2s</resend>
  <resend>s2s</resend>
</dnsrv>

The configuration is a list of services to try for during the resolution request. This particular list has two items. The first has the service="_jabber._tcp" attribute that says "try for the Jabber (via TCP) service when trying to resolve a name (using a SRV record lookup request) and if successful, send the packet on to the s2s component". The second is the default which says "If you've reached here in the list and haven't managed to get a resolution for a particular service, just resolve it normally (using a standard resolver call) and send it on to the s2s component". [12]

The _jabber._tcp is not Jabber configuration syntax, it is the prefix format to use with a domain name when making DNS SRV lookups. [13]

Let's look at what happens in a typical request of dnsrv; to set the scene, a client connecting to the Jabber server to which this dnsrv component instance is connected has requested software update information (see the section called Update Info Request) and as no local component with the identification or filter that fits the hostname update.jabber.org was found in the configuration, a request to resolve and route to this hostname is passed on to the dnsrv component.

  1. The component receives a request for update.jabber.org

  2. Resolution attempt for first <resend/> tag in the list - this is the one that implies a SRV lookup by specifying the _jabber._tcp service definition.

  3. The SRV lookup fails - there are no SRV records maintained for the Jabber service for update.jabber.org.

  4. Resolution attempt for second (and last) <resend/> tag in the list. No service is specified in this tag, so a normal resolution lookup is made.

  5. The lookup is successful, and returns an IP address.

  6. The success means that we've got a match, and the packet destined for update.jabber.org can be passed on to the component specified as next in the chain, which is s2s, as specified in the tag:

    <resend>s2s</resend>

Component Connection Method

The dnsrv component is loaded as a shared library with the library load method:

<load>
  <dnsrv>./dnsrv/dnsrv.so</dnsrv>
</load>

and the dnsrv() function is called when loading is complete to initialise the service.

Component Instance: conf

The Conferencing component is a service that provides group chat facilities in a Jabber environment. Rooms can be created and people can join and chat, in a similar way to how they do in IRC (Internet Relay Chat) channels. The component instance described by the configuration XML in Example 4-16 is shown in diagram form in Figure 4-13.

Figure 4-13. Diagram view of conf component instance

+------+                      
| conf |                    
+------+-----------------------+ 
|                      service |
|--> host    conference.yak    |  
|--> load    conference.so     | 
|--> config  public, vCard,    | 
|            history, notice   |
|            room              |
+------------------------------+ 

Example 4-16. jabber.xml configuration for the conf component instance

<service id='conf'>

  <host>conference.yak</host>

  <load>
    <conference>./conference-0.4.1/conference.so</conference>
  </load>

  <conference xmlns="jabber:config:conference">
    <public/>
    <vCard>
      <FN>yak Chatrooms</FN>
      <DESC>This service is for public chatrooms.</DESC>
      <URL>http://yak/chat</URL>
    </vCard>
    <history>20</history>
    <notice>
      <join> has become available</join>
      <leave> has left</leave>
      <rename> is now known as </rename>
    </notice>
    <room jid="kitchen@conference.yak">
      <name>The Kitchen</name>
      <notice>
        <join> has entered the cooking melee</join>
        <leave> can't stand the heat</leave>
        <rename> now answers to </rename>
      </notice>
    </room>
  </conference>

</service>

The component acts as a sort of third party, and all interaction between room participants are made through this third party. This makes it possible to support privacy (such as using nicknames to hide users' real JIDs) and other features.

Component Type and Identification

The Conferencing component is identified to the backbone as a service:

<service id="conf">

and is given the identity "conf", with which the component instance will register itself when loaded.

Host Filter

By convention, it is often the case that the Conferencing component is addressed (by clients) as 'conference.<hostname>'; we see that convention has been followed in that the host filter for this instance is

<host>conference.yak</host>

which means that all packets destined to any id at the hostname conference.yak will be sent to the conf component instance. This matches the identification of this service in the <browse/> section of the jsm custom configuration.

Custom Configuration

Configuration of the Conferencing component is straightforward and is identified with the jabber:config:conference namespace:

<conference xmlns="jabber:config:conference">
  ...
</conference>

We can see from the contents of the custom configuration that there are a number of elements:

  • Public or private service

    <public/>

    Specifying (with the <public/> tag) that a conference service is public means that users are allowed to browse the elements that the service is controlling, namely the rooms. Rooms are either pre-created or created on the fly by the first user to specify a new name when requesting to join a room. Specifying (with the <private/> tag) that a conference service is private means that users are only allowed to browse rooms that they already know about, meaning rooms in which they're already present.

  • vCard

    <vCard>
      <FN>yak Chatrooms</FN>
      <DESC>This service is for public chatrooms.</DESC>
      <URL>http://yak/chat</URL>
    </vCard>

    The conference service component can have its own vCard information which can be requested at any time. Here is where that vCard information can be maintained. Like the vCard for the jsm service, this particular definition only uses a few of the many possible vCard fields.

  • Message history

    <history>20</history>

    When you join a room, it is sometimes useful to see some of the most recent messages from the room's conversation(s). With the <history/> tag you can specify how many previous messages are relayed to new room joiners.

    If you don't specify a <history/> tag a default value of 10 will be used.

  • Action Notices

    <notice>
      <join> has become available</join>
      <leave> has left</leave>
      <rename> is now known as </rename>
    </notice>

    There are three main 'events' that happen with users and rooms. A user enters a room; a user leaves a room; a user changes his nickname. When any of these events occurs, the conference service component sends some text to the room to notify the participants. You can modify the text that gets sent with the tags in the <notice/> configuration element.

  • Rooms

    <room jid="kitchen@conference.yak">
      <name>The Kitchen</name>
      <notice>
        <join> has entered the cooking melee</join>
        <leave> can't stand the heat</leave>
        <rename> now answers to </rename>
      </notice>
    </room>

    A room is normally created when a user requests to join a room that doesn't already exist - the requesting user is determined to be the room's owner. It is also possible to pre-create rooms when the service starts up; you can define rooms to be pre-created with the <room/> tag. Each room has a JID. Optionally you can give the room a name (which may be displayed by clients as the room's title), and its own action notices.

    There are other settings for rooms that you can specify within a <room/> tag, and these are shown in Table 4-5.

Table 4-5. Conference room settings

SettingDescription
<nick/>This signifies that a nickname is required for entry to the room. If one is not specified (in the join request) a nick will be constructed for the user dynamically, usually the JID with a numeric suffix to make it unique in the room.
<secret/>Rooms can be protected from unauthorized entry by specifying a secret which will be required on entry.
<privacy/>This tag signifies that a privacy mode is supported, which means that users' real JIDs will be hidden from browsing requests.

Component Connection Method

The Conferencing component is compiled into a shared object library (./conference-0.4.1/conference.so) and is connected to the Jabber backbone with the library load method:

<load>
  <conference>./conference-0.4.1/conference.so</conference>
</load>

Once loaded, the function conference() is called to initialize the component and perform setup tasks, such as creating rooms specified in the configuration.

Component Instance: jud

As mentioned already, the JUD is a user directory service that provides storage and query facilities for user name and address data. Figure 4-14 shows, in diagram form, the XML configuration for the jud component instance in Example 4-17.

Figure 4-14. Diagram view of jud component instance

+-----+                      
| jud |                    
+-----+------------------------+ 
|                      service |
|--> host    jud.yak           |  
|--> load    jud.so            | 
|--> config  vCard             | 
+------------------------------+ 

The JUD that is defined here relies upon the xdb component for data storage and retrieval services, which in turn means that in this case, the data is stored in XML format in a file under the directory defined in the <spool/> tag in the xdb component instance's definition. All the data managed by the JUD is stored in one lump, with no specific JID associated with it; this means that xdb's engine, xdb_file, will store it as a single file called global.xml under the directory named after the JUD 'hostname' jud.

Example 4-17. jabber.xml configuration for the jud component instance

<service id="jud">

  <host>jud.yak</host>

  <load>
    <jud>./jud-0.4/jud.so</jud>
  </load>

  <jud xmlns="jabber:config:jud">
    <vCard>
      <FN>JUD on yak</FN>
      <DESC>yak User Directory Services</DESC>
      <URL>http://yak/</URL>
    </vCard>
  </jud>

</service>

Component Type and Identification

JUD is clearly a service component, and is identified as such with this tag:

<service id="jud">

The name given to the component instance is "jud".

Host Filter

Requests of the JUD, such as searches or registrations (a user 'registers' with the JUD and thereby causes his name and address details to be stored by the JUD) must be directed specifically at the JUD, which we have identified in the <browse/> area of our jsm configuration (see the section called Custom configuration) as jud.yak.

As we have identified the JUD in this way, requests will reach the JUD by way of this hostname, which is therefore what we want to filter on:

<host>jud.yak</host>

Requests to any other hostnames are not appropriate for the JUD to handle and will therefore be filtered out.

Custom Configuration

There is not much to configure in the JUD; it is a simple user directory service and many of the features are currently hardcoded - where the data is stored, what data fields are stored per JID, and so on. The only configuration we can maintain is the JUD's vCard information. Just as the Jabber server itself and each user can have a vCard, components can have vCards too. These component vCards can be requested in the same way. [14]

<jud xmlns="jabber:config:jud">
  <vCard>
    <FN>JUD on yak</FN>
    <DESC>yak User Directory Services</DESC>
    <URL>http://yak/jud</URL>
  </vCard>
</jud>

The namespace that declares the JUD configuration is jabber:config:jud.

Component Connection Method

The JUD defined here is implemented as a set of C programs compiled into a shared object (./jud-0.4/jud.so) library. It is connected to the backbone with the library load connection method:

<load>
  <jud>./jud-0.4/jud.so</jud>
</load>

and the function jud() is called to initialise the component.

Component Instance: s2s

Just as the c2s component provides the Client (to Server) Connections service, so the s2s component provides the Server (to Server) Connections service. The XML configuration that describes the s2s component is shown in Example 4-18, and is represented in diagram form in Figure 4-15.

Figure 4-15. Diagram view of s2s component instance

+-----+                      
| s2s |                    
+-----+------------------------+ 
|                      service |
|--> host    (s2s)             |  
|--> load    dialback.so       | 
|--> config  legacy, ip, karma | 
+------------------------------+ 

Example 4-18. jabber.xml configuration for the s2s component instance

<service id="s2s">

  <load>
    <dialback>./dialback/dialback.so</dialback>
  </load>

  <dialback xmlns='jabber:config:dialback'>
    <legacy/>
    <ip port="5269"/>
    <karma>
      <init>50</init>
      <max>50</max>
      <inc>4</inc>
      <dec>1</dec>
      <penalty>-5</penalty>
      <restore>50</restore>
    </karma>
  </dialback>

</service>

Component Type and Identification

The component type is service, and the instance here is identified as "s2s":

<service id="s2s">

Host Filter

As with the c2s component instance definition, no explicit host filter is set here for the s2s. The identification of the component instance as "s2s" acts as an ersatz host filter.

Custom Configuration

The configuration for the s2s is similar to that of the c2s; after all, it is about managing connections to other hosts. The configuration namespace is, however, a little odd:

<dialback xmlns="jabber:config:dialback">

'Dialback'? Well, in order to prevent spoofing on a connecting server's part, the s2s component implements a identity verification mechanism that is used to check that a connecting server is who it says it is. See the sidebar entitled "Dialback" for more details.

Server-to-server namespace: As the namespace for the exchange of document streams in a client-to-server connection is jabber:client, so the namespace for the exchange of document streams in a server-to-server connection is jabber:server.

There are three immediate child tags in the configuration wrapper tag:

  • <legacy/>

    This acts as a flag that allows (or not, if it is absent) 'legacy' Jabber servers to connect. A 'legacy' Jabber server is one that has version 1.0, and, of more relevance, no support for the dialback mechanism. Without the tag, an incoming connection from a version 1.0 Jabber server that didn't support dialback would be refused.

  • <ip/>

    While a normal Jabber server listens for client connections on 5222, it listens for connections from other Jabber servers on port 5269. This is specified with the <ip/> tag, which has the same characteristics as the <ip/> tag in the c2s configuration settings (more than one tag allowed, specific IP address optional).

  • <karma/>

    Karma is used in the s2s component to control connection traffic, just as it is used in c2s. See the "<io/> Section" below for more details.

Component Connection Method

The library load method is used to connect the s2s component to the backbone:

<load>
  <dialback>./dialback/dialback.so</dialback>
</load>

The dialback() is called in the shared library after it has been loaded.

io Section

The io section of the jabber.xml configuration file, shown in Example 4-19 and represented in diagram form in Figure 4-16, is where a number of settings relating to socket communication with the Jabber server are set.

Figure 4-16. Diagram view of io section

+----+                      
| io |                    
+----+-----------------+ 
|--> rate   ...        |  
|--> karma  ...        | 
|--> ssl    ...        | 
|--> allow  ...        | 
|--> deny   ...        | 
+----------------------+ 

Example 4-19. jabber.xml configuration for the io section

<io>

  <karma>
    <heartbeat>2</heartbeat>
    <init>64</init>
    <max>64</max>
    <inc>6</inc>
    <dec>1</dec>
    <penalty>-3</penalty>
    <restore>64</restore>
  </karma>

  <rate points="5" time="25"/>

</io>

Although a distinct section, io does not describe a component with custom configuration or a connection method - the contents are merely settings. Let's examine each of these settings here.

<rate/>

The <rate/> tag afford us a sort of connection throttle by allowing us to monitor the rate at which incoming connections are made, and to put a hold on further connections if the rate is reached.

The rate is calculated to be a number of connection attempts - from a single IP address - within a certain amount of time. We can see these two components of the rate formula as attributes of the <rate/> tag itself:

<rate points="5" time="25"/>

This means acceptance of incoming connections from an individual IP address will be stopped if more than 5 connection attempts (points) are made in the space of 25 seconds (time).

The 'rating' (the throttling of connection attempts) will be restored at the end of the period defined (25 seconds in this case).

The effect of a <rate/> tag in this io section is server-wide; all socket connections (for example c2s) can be rate-limited. If there is no specific <rate/> specification in a particular service that listens on a socket for connections, then the specification in this io section is used. If no <rate/> tag is specified in this io section, then the server defaults are used - these are actually the same as what's explicitly specified here.

<karma/>

Like the <rate/> tag, <karma/> is used to control connectivity. Whereas rating helps control the number of connections, karma allows us to control the data flow rate per connection once a connection has been made.

The concept of karma is straightforward; each socket has a karma value associated with it. We can understand it better if we think of it as each entity (connecting through a socket) having a karma value. The higher the value - the more karma - an entity has, the more data it is allowed to send through the socket. So as rating is a throttle for connections, so karma is a throttle for data throughput.

There are certain settings that allow us to fine-tune our throughput throttle. Table 4-5 lists these settings, along with the values explicitly set in each of the c2s and s2s component sections in our jabber.xml file. Notice how the settings for the Server (to Server) Connections component are considerably higher than those for the Client (to Server) Connections - this is based on the assumption that server-to-server traffic will be greater than client-to-server on a socket by socket basis.

The relationship between an entity's karma and how much data it is allowed to write to the socket is linear - in fact the amount is

(karma value * 100)
and this every 2 seconds. The multiplier (100) and the karma period (2) are hardcoded into the server - a recompilation would be required to change these values.

Over time, an entity's karma value will increase, up to a maximum value (we need a ceiling on how much we're going to allow an entity to send!) every karma period (2 seconds).

The same karma formula is used to penalize an entity for sending too much data. If more than (karma * 100) bytes are sent within a certain period, the entity's karma value is decreased. Once the value reaches zero, it is plunged to a negative number meaning that the entity must take a breather until the value grows back to zero (over time, it will). At this point, the value will be 'restored' to a value that gives the entity chance to start sending data again.

Table 4-6. Settings for karma control, with c2s and s2s values

Settingc2s valuess2s valuesDescription
<init/>1050The initial value for karma on a new socket
<max/>1050The maximum karma value that can be attained by a socket
<inc/>14By how much the karma value is incremented (over time)
<dec/>11By how much the karma value is decremented in a penalty situation
<penalty/>-6-5The karma value is plunged to this level once it falls to zero
<restore/>1050The karma value is boosted to this level once it rises (after a penalty) to zero.

<ssl/>

If you have compiled your Jabber server with SSL (see Chapter 3) and want to use SSL-encrypted connections, you will have to have specified the <ssl/> tags in the configuration of the c2s component instance. Furthermore, you must specify the location of your SSL certificate and key file. There is an <ssl/> tag in this io section for this purpose.

You can have separate files for each IP address specified in the c2s component instance configuration's <ssl/> tag. Example 4-20 shows the specification of two .pem files - one for each of two IP addresses.

Example 4-20. Specifying SSL certificate & key files per IP address

<ssl>
  <key ip="192.168.0.4">/usr/local/ssl/certs/ks1.pem</key>
  <key ip="192.168.9.1">/usr/local/ssl/certs/ks2.pem</key>
</ssl>

<allow/> and <deny/>

You can control at the IP address and network level who can connect to your Jabber server with the <allow/> and <deny/> tags.

The default (when no tags are specified) is to allow connections from everywhere. If you use <allow/> tags, then connections will be allowed only from the addresses or networks specified. If you use <deny/> tags, then connections will be denied from those addresses or networks specified. If you have both <allow/> and <deny/> tags, the intersection of addresses between the two tag sets will be denied - in other words, <deny/> overrides <allow/>.

The tags wrap individual ip addresses, which are specified using the <ip/> tag, or network addresses, which are specified using the <ip/> tag in combination with the <mask/> netmask tag. Example 4-21 shows connections to a Jabber server being limited to hosts from two internal networks with the exception of one particular IP addresses, and a specific host on the Internet.

Example 4-21. Using <allow/> and <deny/> to control connections

<allow>
  <ip>192.168.10.0</ip>
  <mask>255.255.255.0</mask>
</allow>

<allow>
  <ip>192.168.11.0</ip>
  <mask>255.255.255.0</mask>
</allow>

<allow>
  <ip>195.82.105.244</ip>
</allow>

<deny>
  <ip>192.168.11.131</ip>
</deny>

pidfile Section

The pidfile section simply specifies the name of the file where the process ID (PID) of the Jabber server will be written at startup. In this case the name of the file is ./jabber.pid.

The XML describing this section is shown in Example 4-22, and is represented in diagram form in Figure 4-17,

Figure 4-17. Diagram view of pidfile section

+---------+                      
| pidfile |                    
+---------+------------+ 
|--> jabber.pid        |  
+----------------------+ 

Example 4-22. jabber.xml configuration for the pidfile section

<pidfile>./jabber.pid</pidfile>

Notes

[1]

Remember that if no <host/> is specified, the instance id - in this case "sessions" is used instead.

[2]

The queries to retrieve a list of online users are addressed to the server directly - here the recipient JID is the servername; the iq:admin query version actually requires a resource of 'admin' to be suffixed to the server name too. For more information on the makeup of JIDs, see Chapter 5.

[3]

Actually, that's not true - it was just to catch those of you who were falling asleep - Jabber clients can use the Out Of Band (OOB) namespace to negotiate file transfers between themselves. See Part II for more details.

[4]

The JUD is referred to here as a 'local' JUD because there's a central JUD running on jabber.org that every Jabber user can connect to and use (even if they're on a different Jabber server); the word 'local' makes the distinction that the JUD is running locally to the Jabber server to which the Jabber user is connected.

[5]

in conjunction with the xdb component - see later.

[6]

If the connection between the client and the server is encoded using SSL, then the plaintext password travels through an encrypted connection.

[7]

An example of this would be JUD's usage of xdb (and implicitly xdb_file in our configuration) - a file called global.xml is used to store the user directory information that JUD manages.

[8]

Some of these are being developed and are available right now

[9]

Only do this if you're sure you know what you're doing.

[10]

Actually, the <logtype/> tag is more of a filter (like <host/>) than configuration. But that's splitting hairs.

[11]

Or on a server offering another IM service, for example - this is planned for the future.

[12]

gethostbyname()

[13]

See RFC 2782 for more details.

[14]

Ok, the vCard in this case is actually for the jsm, which is the heart of the Jabber server...