# jabberd2 Programmers Guide

## expat - XML parsing library

The XML parsing requirements of the jabberd system are handled by the ubiquitous Expat library. Since we need a parser that is namespace aware, v1.95 is the version in use.

Expat is widely used and understood, and it doesn't make sense to repeat a long description of the library here. More information can be found on the Expat homepage.

## mio - Managed I/O

MIO is an event wrapper around UNIX file descriptors. The application can associate a callback function with each file descriptor it is interested in monitoring. When some kind of activity occurs on the file descriptor, the callback is fired. For network-driven applications such as jabberd, this is very useful, as it allows the main loop of the application to be reduced to a simple call into the MIO subsystem.

### Data types

- MIO context - `mio_t`

  `mio_t` is an opaque type that holds all the state information for the file descriptors being handled by the context. It is created by `mio_new()`, freed by `mio_free()`, and passed as the first argument to every other MIO function.

- MIO action (event) - `mio_action_t`

  `mio_action_t` is an enumeration which is passed as the second argument to a callback, to inform the application of which event occurred. It can take one of four values:

  - `action_ACCEPT` - someone has connected to this (listening) file descriptor.
  - `action_READ` - this file descriptor has data waiting to be read.
  - `action_WRITE` - this file descriptor is able to be written to.
  - `action_CLOSE` - this file descriptor has been closed.

- MIO handler (callback) - `mio_handler_t`

  `mio_handler_t` is a prototype for a callback. A callback function should be of the following type:

  `typedef int (*mio_handler_t)(mio_t m, mio_action_t a, int fd, void *data, void *arg)`

  When called, the arguments passed to the callback are as follows:

  - `mio_t m` - the MIO context that is managing the file descriptor.
  - `mio_action_t a` - the action that occurred.
  - `int fd` - the file descriptor that this action occurred on. Note that for `action_ACCEPT`, this argument will be hold the file descriptor of the new connection.
  - `void *data` - action-specific data. This is currently only used for `action_ACCEPT` - when this action occurs, `data` should be casted to `char *`, where it will contain a string representation of the remote IP address.
  - `void *arg` - this is the application-specific data that was registered at the same time the callback was registered with `mio_fd()` or `mio_app()`.

  The return type of the callback function is different depending on the action:

  - `action_ACCEPT` - if the callback returns 0, the newly-accepted file descriptor will be tracked in the MIO context. If it returns non-zero, the connection will be closed.
  - `action_READ` - if the callback returns 0, no further read events will be fired to the callback until `mio_read()` is called on this file descriptor. If it returns non-zero, events will continue to be processed.
  - `action_WRITE` - if the callback returns 0, no further write events will be fired to the callback until `mio_write()` is called on this file descriptor. If it returns non-zero, events will continue to be processed.
  - `action_CLOSE` - the return value is ignored for this action.

### Creating/freeing a MIO context - mio_new(), mio_free()

- `mio_t mio_new(int maxfd)`

  `mio_new()` creates a new MIO context.

  This function takes the following arguments:

  - `int maxfd` - the highest file descriptor (+1) that can be managed by this MIO context.

  This function returns the following values:

  - `NULL` - creation of the MIO context failed for some reason. This is typically caused by a failure to allocate resources.
  - non-`NULL` - creation of the MIO context succeeded. The returned context is ready for use.

- `void mio_free(mio_t m)`

  `mio_free()` frees a MIO context. It does not close any file descriptors that are being managed by the MIO context.

  This function takes the following arguments:

  - `mio_t m` - pointer to the MIO context to free.

  This function returns nothing.

### Setting the callback for a file descriptor - mio_fd(), mio_app()

- `int mio_fd(mio_t m, int fd, mio_handler_t app, void *arg)`

  `mio_fd()` instructs MIO to begin tracking the given file descriptor. Note that the file descriptor will be set to non-blocking mode as a result of this call.

  This function takes the following arguments:

  - `mio_t m` - the MIO context to associate this file descriptor with.
  - `int fd` - the file descriptor to track.
  - `mio_handler_t app` - the callback to invoke when an event occurs.
  - `void *arg` - application-specific data to be passed to the callback.

  This function returns the following values:

  - `< 0` - the file descriptor number is too large for this MIO context to track. The maximum is set by `mio_new()`.
  - `>= 0` - the file descriptor is being tracked.

- `void mio_app(mio_t m, int fd, mio_handler_t app, void *arg)`

  `mio_app()` resets the callback on the given file descriptor. This can only be called on a file descriptor that is being tracked by the MIO context.

  This function takes the following arguments:

  - `mio_t m` - the MIO context this file descriptor is associated with.
  - `int fd` - the file descriptor to reset the callback for.
  - `mio_handler_t app` - the callback to invoke when an event occurs.
  - `void *arg` - application-specific data to be passed to the callback.

  This function returns nothing.

### Requesting notification about file descriptor events - mio_read(), mio_write()

- `void mio_read(mio_t m, int fd)`

  `mio_read()` instructs MIO to process read events for the given file descriptor. When such an event occurs, the application callback for the file descriptor will be called with the `action_READ` event.

  This function takes the following arguments:

  - `mio_t m` - the MIO context this file descriptor is associated with.
  - `int fd` - the file descriptor to process read events for.

  This function returns nothing.

- `void mio_write(mio_t m, int fd)`

  `mio_write()` instructs MIO to process write events for the given file descriptor. When such an event occurs, the application callback for the file descriptor will be called with the `action_WRITE` event.

  This function takes the following arguments:

  - `mio_t m` - the MIO context this file descriptor is associated with.
  - `int fd` - the file descriptor to process write events for.

  This function returns nothing.

### Closing a file descriptor - mio_close()

- `void mio_close(mio_t m, int fd)`

  `mio_close()` is a wrapper around `close()` that also stops the file descriptor from being tracked by the MIO context. You should use this in place of `close()` for a MIO-managed file descriptor.

  This function takes the following arguments:

  - `mio_t m` - the MIO context this file descriptor is associated with.
  - `int fd` - the file descriptor to close.

  This function returns nothing.

### Creating a new file descriptor - mio_connect(), mio_listen()

- `int mio_connect(mio_t m, int port, const char *hostip, mio_handler_t app, void *arg)`

  `mio_connect()` initiates a connection to the given ip/port. This function returns immediately, and the connect continues in the background (in non-blocking mode). The application should call `mio_read()` and/or `mio_write()` after calling `mio_connect()` in order to receive events after the connection has completed.

  If the connect fails, the callback will be called with the `action_CLOSE` event.

  This function takes the following arguments:

  - `mio_t m` - the MIO context that will track this connection.
  - `int port` - the remote port to connect to.
  - `char *hostip` - string representation of the remote IP address to connect to.
  - `mio_handler_t app` - the callback to invoke when an event occurs.
  - `void *arg` - application-specific data to be passed to the callback.

  This function returns the following values:

  - `< 0` - the file descriptor creation or the connect init failed for some reason. `errno` may have more information.
  - `>= 0` - the new file descriptor.

- `int mio_listen(mio_t m, int port, const char *sourceip, mio_handler_t app, void *arg)`

  `mio_listen()` starts a listening socket on the given ip/port. The callback will be called with the `action_ACCEPT` action when a new connection is initiated.

  This function takes the following arguments:

  - `mio_t m` - the MIO context that will track this socket, and newly-accepted connections.
  - `int port` - the local port to listen on.
  - `char *sourceip` - string representation of the local IP address to listen on.
  - `mio_handler_t app` - the callback to invoke when an event occurs.
  - `void *arg` - application-specific data to be passed to the callback.

  This function returns the following values:

  - `< 0` - the file descriptor creation or the listen init failed for some reason. `errno` may have more information.
  - `>= 0` - the file descriptor of the listening socket.

### Process pending events on file descriptors - mio_run()

- `void mio_run(mio_t m, int timeout)`

  `mio_run()` processes pending events on file descriptors being tracked by the given MIO context. It will fire the associated callback if anything interesting has happened to a file descriptor.

  This function takes the following arguments:

  - `mio_t m` - the MIO context to process.
  - `int timeout` - Number of seconds to wait for events for. The call will block for at least this long. To do one check, then return (ie non-blocking behaviour), set this to 0.

  This function returns nothing.

### Extending MIO - backends for event-readiness APIs

TODO

## util - Support utilities

jabberd2 provides a variety of special-purpose utility libraries to aid the programmer with common functions. Some of them contain dependencies on other utilities and in one case (config), also a dependency on Expat. These dependencies are noted.

### access - IP-based access controls

#### Data types

- access context - `access_t`

#### Creating/freeing an access context - access_new(), access_free()

- `access_t access_new(int order)`

- `void access_free(access_t access)`

#### Adding an access control rule - access_allow(), access_deny()

- `int access_allow(access_t access, const char *ip, const char *mask)`

- `int access_deny(access_t access, const char *ip, const char *mask)`

#### Checking whether are not an IP address matches a rule - access_check()

- `int access_check(access_t access, const char *ip)`

### config - XML config files

TODO

### jid - Jabber ID manipulation

TODO

### log - Logging (file/syslog)

#### Data types

- log context - `log_t`

#### Creating/freeing a log context - log_new(), log_free()

- `log_t log_new(int syslog, const char *ident, int facility)`

- `void log_free(log_t log)`

#### Writing data to a log - log_write()

- `log_t log_write(log_t log, int level, const char *msgfmt, ...)`

### nad - Lightweight XML DOM

TODO

### pool - Memory pools

TODO

### rate - Rate controls

#### Data types

- rate context - `rate_t`

#### Creating/freeing a rate context - rate_new(), rate_free()

- `rate_t rate_new(int total, int seconds, int wait)`

- `void rate_free(rate_t rt)`

#### Updated rate counts - rate_add(), rate_reset()

- `void rate_add(rate_t rt, int count)`

- `void rate_reset(rate_t rt)`

#### Checking rate limits - rate_check(), rate_left()

- `int rate_check(rate_t rt)`

- `int rate_left(rate_t rt)`

### serial - Data serialisation

#### Retrieving values from a buffer - ser_string_get(), ser_int_get()

- `int ser_string_get(char **dest, int *source, const char *buf, int len)`

- `int ser_int_get(int *dest, int *source, const char *buf, int len)`

#### Adding values to a buffer - ser_string_set(), ser_int_set()

- `void ser_string_set(char *source, int *dest, const char **buf, int *len)`

- `void ser_int_set(int source, int *dest, const char **buf, int *len)`

### sha - SHA1 hash generation

#### Generating a SHA1 hash - shahash(), shahash_r()

- `char *shahash(char *str)`

- `void shahash_r(const char *str, char hashbuf[41]`

### str - String manipulation

### spool - String pools

#### Data types

- spool context - `spool`

#### Creating a spool context - spool_new()

- `spool spool_new(pool p)`

#### Adding strings to a spool context - spool_add(), spooler()

- `void spool_add(spool s, const char *str)`

- `void spooler(spool s, ...)`

#### Getting the contents of a spool context - spool_print()

- `char *spool_print(spool s)`

#### Concatenating strings on the fly - spools()

- `void spools(pool p, ...)`

### xhash - Hash tables

TODO

## sx - XML streams abstraction

### Data types

TODO

### Creating/freeing an XML stream - sx_new(), sx_free(), sx_env_new(), sx_env_free()

TODO

### Beginning and ending an XML stream - sx_client_init(), sx_server_init(), sx_auth(), sx_close()

TODO

### Using an XML stream

TODO. Creating a stream. Connecting it and performing any needed authorizations or negotiations. Writing nads to the stream. Processing nads parsed by the stream. Shutting down a stream. Handling I/O for the stream. Dealing with network or protocol errors.

### Providing an `sx_callback_t` function

An XML stream communicates events and data to the rest of the program by invoking the callback function which was given as an argument to `sx_new()`. The first two arguments of the callback function are the `sx_t` which is invoking the callback, and an enumerated value (`sx_event_t`) which indicates the reason the callback was invoked. The interpretation of the third argument (a `void *`) and the return value (an integer) depends on the value of the event argument.

The event_WANT_READ and event_WANT_WRITE events indicate that the xml stream is expecting input from the underlying octet-stream or has data it wishes to write to that stream. The callback should invoke either `sx_can_read()` or `sx_can_write()` as appropriate. If the read or write can be performed immediately without blocking, it can be invoked directly from the callback; otherwise, the callback should schedule the function to be called when data (or buffer space) is available. The `data` argument and the return value are not used for these event types.

event_READ and event_WRITE are requests for the callback to perform IO on behalf of the xml stream. The `data` argument is a pointer to an `sx_buf_t`. For event_READ, the callback should read into the specified buffer, adjust the buffer's len to indicate the number of bytes read, and return a nonnegative number to indicate success. For event_WRITE, the callback should return the number of bytes written from the buffer. A negative return value indicates that an error (including end-of-file) has occurred and the stream must be shut down.

TODO: nonblocking IO and event loops; use of mio_* functions.

event_STREAM, event_OPEN, event_CLOSED, event_ERROR: TODO. Being notified of changes in the stream's state.

event_PACKET: TODO. Processing a packet received by the stream.

### Implementing a stream plugin

TODO: What a plugin is for and what it can do. Existing stream plugins. How to create a new stream plugin. Processing sent and received bytes. Processing sent and received nads.

### Buffer management functions used with XML streams

TODO: sx_buf_t functions and memory management.

## Extending the session manager

### Storage drivers

TODO

### Protocol modules

TODO

## Extending the client-to-server connector

### Authenticator modules

TODO

### Using the pipe authenticator

TODO

## Internal protocols

### Session control protocol

TODO

### DNS resolution protocol

TODO