An Introduction to Components

Thomas Muldowney

Jabber.Org


          <temas@jabber.org>
          temas@jabber.org
        

This document has been placed in the public domain.

Revision History
Revision 0.1 2001-11-19 tjm
Initial Revision

Abstract

A simple introduction to authoring a Jabber Component.


Table of Contents

Introduction
Component Types
Connecting and Authenticating
Normal Operation
Advanced Operation
XDB
Logging
Route

Introduction

One of the primary methods of extending the Jabber platform is through components that add functionality to the system. Components generally use the same protocol as all other Jabber pieces (clients, server to server, etc), but they do have a few subtle differences that can be confusing at first. This introduction will serve as a starting point to understanding Jabber component development.

Component Types

The first choice to be made is which type of component to create: a loaded module, an accept, a connect, or an executed component. While all of these generally interact the same they do have some major differences. Let's examine each type and see why they would be a good or bad choice.

The loaded module often seems like an appealing choice because most of the current components are written using it, but it is strongly frowned upon. Using a loaded module causes the component to be bound to the exact internal model of a single server, and not globally usable. It also generally makes the programming a bit more difficult because you can not use the APIs you are most comfortable with, rather the ones that are built into the system you are targetting. You do receive slight speed benefits from the loaded module because the XML is not copied over the wire as many times. Overall, though, the loaded module is not a wise choice.

The accept component is the suggested type of component now. An accept component connects to a jabberd and authenticates itself as a certain id on that jabberd. It then begins to receive packets bound to the JID that it registered as. The power of this, is that it can connect to any jabberd that understands the simple accepting procedure (this is considered core functionality, and practically a requirement of any server claiming it supports Jabber). This works well for a component that is intended to be ran on all servers seperately such as gateways to other networks and services like Jogger.

The connect component is very similar to the accept component, but the jabberd connects to the component and authenticates against it. This is very helpful when the component author does not wish to actually distribute a component, but rather just host it themselves.

Finally we have the executed type of component. This type of component is ran locally by the jabberd process when it starts up, and communicates through the standard input and output. Generally it is not well accepted, but is very handy for simple components made in scripting languages where sockets can cause unnecessary overhead.

Connecting and Authenticating

Once you have a type of component selected you have to connect and authenticate with the jabberd before it will start sending you packets (except for loaded modules, they are automatically trusted). This is all done using the normal <stream:stream> negotiation, followed by a <handshake>.

Table 1.

Type Namespace
Load Not Used
Accept jabber:component:accept
Connect jabber:component:connect
Execute jabber:component:execute

The <stream:stream> negotiation is generally the same as the clients use but with different namespaces. Shown in the namespace table are the namespaces used in the intial negotiation based on the component type. The other important part of the negotiation are the to and from attributes. Based on the direction of the connection you need to have the correct attribute be the id that you were configured to use. The to attribute for accept and execute, and the from attribute for connect.

Example 1. Example Accept Negotiation

<stream:stream xmlns='jabber:component:accept' stream:xmlns='http://etherx.jabber.org/streams' to='example'>

<stream:stream xmlns:stream='http://etherx.jabber.org/streams' id='3BF96D32' xmlns='jabber:component:accept' from='example'>

Once the stream negotiation is complete authentication begins. All authentication for components is done using the <handshake> element. The initiator of the connection (jabberd or component) sends the <handshake> element with secret and session ID from the stream negotiation SHA1 encoded in lower case hex. So if we use the stream id information from Example Accept Negotiation (3BF96D32) and a secret of test we would have to send:

<handshake>aaee83c26aeeafcbabeabfcbcd50df997e0a2a1e</handshake>
If the handshake is valid, the recipient will send:
<handshake/>
Otherwise an error will be sent and the stream and connection closed. Now that authentication is complete the component will begin receiving packets and may send them to the jabberd to be deliverd.

Normal Operation

Normal operation for a component is very straightforward. Packets will come in from jabberd, and the packets may be sent out through the jabberd. The one important thing to remember is that the packets sent out must have the from attribute set, and the hostname must match the name of the component. Otherwise errors and other significant information will never make it back to the component. Pretty much any valid XML can be sent through if it has a to and from attribute, there are a few tags to watch out for though: <xdb>, <log>, and <route>. These tags are part of the internal protocol and have specific usage associated with them, and will be discussed later.

It is highly suggested that most components support as many of the basic namspaces as possible (iq:register, iq:time, iq:version, etc), as well as iq:browse. If the component is a gateway to another network or has user sessions in it, it is also recommended that iq:last and iq:gateway are supported. This makes it easier for clients to interact with the component.

Advanced Operation

Although components are generally very simple in normal operation, they can use many of the more advanced facilities of jabberd. More specifically the component can access XDB, log, and act as a session controller.

XDB

XDB is a method to interact with the data storage associated with users and globally for components, using the <xdb> element. When a component wishes to retrieve information it addresses the <xdb> to the user (or it's own name for it's personal, global information) with the type set to get and the ns attribute set to the namespace to retrieve. The xdb server will then reply with either nothing (indicating nothing was found in the XDB) or the valid data. An example of this is shown in XDB Get Example:

Example 2. XDB Get Example

<xdb type='get' to='temas@server' from='component' ns='jabber:iq:auth'/>

<xdb type='result' to='component' from='temas@server' ns='jabber:iq:auth'><password xmlns='jabber:iq:auth'>test</password></xdb>

Putting information into the XDB is very similar to this. The only difference is the use of set instead of get in the type attribute. The information being set into the XDB is put in the <xdb> element and should be in the namespace specified by the ns attribute. An example of this is shown in XDB Set Example

Example 3. XDB Set Example

<xdb type='set' to='temas@server' from='component' ns='testeroo'><test xmlns='testeroo'>test info</test></xdb>

<xdb type='result' to='component' from='temas@server' ns='testeroo'><test xmlns='testeroo'>test info</test></xdb>

Logging

Logging is a necessary functionality for all systems, because system administrators can configure different logging methods in their jabberd configuration files it is often helpful for the components to log through jabberd. Components use the <log> element to interact with the logging system. It's very simple to use, just set the type attribute to the desired level (most commonly one of: warn, alert, or error), and set the from attribute to the component name (or name the log should come from), and then put the log message inside the element. An example of this is shown in Logging Example

Example 4. Logging Example

<log type='warn' from='component'>You forgot to enable the foo feature</log>

One slightly special case of logging is the record type. Record is designed to track the sessions of users and their activity, anything sent with the type set to record will end up in the record log file which is usually seperate from the other log files. Really anything can be configured to log seperately or in a special way, but the default is all types to one file, and record to the other.

Route

<route> allows for controlling a users session with JSM (Jabber Session Manager). This is a complex topic I'll save for the next revision.