The Dive Plugin Interface

Reference Document
Web site: <http://www.sics.se/dive/manual/plugin.html>

Mårten Stenius - <mst@sics.se>
Swedish Institute of Computer Science
Stockholm, September 1997

1. Introduction

This document describes the basic plugin functionality in Dive[1] and its interface. Background knowledge about C, general operating system design, and the design and implementation of Dive is highly recommended if not required.

The functionality described here is to be seen as a first step towards enabling a more modular design of Dive, and may in the future be extended to incorporate different classes of plugins, enabling simple pluggable replacements of render modules, distribution mechanisms, object behaviours languages, etc.

A Dive plugin is basically just a  dynamically loadable library, providing a set of symbols and functions recognized by Dive. When the plugin is loaded into the Dive process space, which is done runtime, these symbols are looked up by the Dive plugin interface and called, as described below.

The benefits of such a modular redesign includes simpler reconfiguration of the software - even runtime - without recompiling or restarting, greater freedom in experimenting with the integration of new technologies into Dive, still with full access to the "core" C interface of Dive. Furthermore, this is a step towards even further enabling Dive to suit different platforms with different capabilities and approaches by making different parts of the system easy to change and configure.

2. The Basic Plugin Interface

This interface allows the runtime loading of simple libraries into the Dive process. The interface specification is found in  dive/plugin.h.

Implementation of a Plugin

The only requirement for a plugin library is that it defines two functions:

int dive_plugin_init() - will be called by Dive when the plugin is loaded into memory.

int dive_plugin_exit() - will be called when the plugin will be deactivated (typically when the Dive process exits).

The integer return value informs Dive if the execution of the function was successful: 0 should be returned if no problems occured, -1 otherwise. If dive_plugin_init returns -1, the plugin will not be actively handled by the Dive layer, but still reside in memory (depending on implementation, operating system and so on).

Typical actions performed in dive_plugin_init might be to register callbacks on various events in the virtual environment, to register new Dive/Tcl [4,5] functions that it implements, or to create some Dive objects for later use. Similarly, dive_plugin_exit should clean up by removing objects, deregistering callbacks, etc.

The plugin need not be linked with any the Dive libraries. If it wishes to interface the Dive routines, it needs to include the standard Dive include files (typically "dive/dive.h" and any modules headers as required). On UNIX platforms, it is sufficient to compile the plugin as a shared library, and make sure that the Dive plugin interface can find it (see below).

Implementation of the Dive Plugin Interface

The plugin implementation in Dive is added to the src/ hierarchy, and found in plugin.c and plugin.h. These functions should not be used in the actual implementation of a plugin, they should only be used in the "core" of a Dive process for general plugin searching, loading, etc. The following functions are currently defined:

int plugin_init()

Should be called at startup by any Dive process that wishes to handle plugins (this is done by for instance the diva and vishnu applications). This function sets up the plugin records, and loads any plugins specified in the .dive_plugins file. A default version is found in dive/data/.dive_plugins, and the user may put a personal version in his/her home directory. Also, a specific plugin file can be pointed out by the plugin_file configure option. The format of these files is simple: a text file with one file name per line. Empty lines or lines starting with '#' will be ignored.

dive_plugin_p plugin_load(char *filename)

Will load a plugin from the file specified in filename. This may either be a full path, or just the name of a file. In the latter case, the file will be searched for in the DIVEPATH. A plugin name for further reference in Dive will be derived from this filename/path, by stripping any extensions and directory paths from the string. For example, a plugin loaded by calling dive_plugin_load("/home/foo/example.so") would be named "example". Currently, reloading of plugins with the same (derived) name is not allowed, for instance, any subsequet attempt to load a new module with the name "example" would be ignored. A pointer to a new plugin control record is returned on success, on failure NULL is returned. If there already was a plugin with a matching name, a pointer to that plugin record will be returned.

dive_plugin_p plugin_get(char *name)

Returns a pointer to the plugin control record the currently loaded plugin matching the name parameter, such as "example" mentioned above. Returns NULL if no such plugin is loaded.
 

3. A Simple Plugin Example

This is an example of the implementation of a very simple plugin with the non-informative name foo. This plugin registers a callback that prints a short message each time a new object is created in the environment interfaced by the Dive process. The plugin source file (foo.c) may look like:

#include <stdio.h>
#include "dive/dive.h"

void foo_cb(objid_t *id, objid_t *origin, void *arg)
{
  printf("foo: New object!\n");
}

int dive_plugin_init()
{
  printf("This is plugin foo being inited in DIVE version %s!\n", DIVE_VERSION);
  callback_register(ENTITY_NEW_EVENT, foo_cb, NULL);
  return 0;
}

int dive_plugin_exit()
{
  printf("This is plugin foo exiting!\n");
  callback_unregister(ENTITY_NEW_EVENT, foo_cb);
  return 0;
}

This code then needs to be compiled as a dynamically loadable (shared) library. On a UNIX platform this is typically done by using the -shared command-line switch with the compiler, even though this interface is bound to vary with different operating systems and compilers. A compile line may look something like:

gcc -c -o foo.so -shared -I/home/some_user/dive/include/ -I/home/some_user/dive foo.c

Then, Dive must be told to load the plugin (library), by adding a reference to the .dive_plugins file, such as the one found in dive/data, or a personalised version in the home directory of the current user. So .dive_plugins should contain a line similar to:

/home/some_user/foo.so

or just:

foo.so

if the library is placed somewhere in the DIVEPATH.

Once this is done, the plugin should be loaded as soon as some of the default Dive proceses is started (such as vishnu). If it is successfully loaded, vishnu should now be enriched with a piece of code that puts out annoying messages as soon as a new dive object is created.

The implementations of more useful and innovative plugins are left to the reader's imagination and programming skills.

4. Security Issues

An important questions is, as always, security, such as whether we should have a way of layering the level of access a plugin will have to the underlying Dive and system libraries, depending on how "trusted" it is. Currently, a plugin can basically do anything that can be done from the core Dive program itself (since it is typically a C library dynamically loaded directly into the process space), including system calls, so any plugin "source" must be highly trusted. Such security questions, however, are known to be complex and difficult, requiring a high level of encapsulation and control (see e.g. the implementation of the Java[5] virtual machine), so currently the way to go may just be to follow the approach used for plugins in for instance Tcl/Tk[3], that is, to let the end-user decide whether a particular plugin is trusted, just as for any application that is downloaded.

References

[1] The Dive User and Reference Manuals, available at <http://www.sics.se/dive/manual/manual.html>
[2] Olof Hagsand, "Interactive Multiuser VEs in the DIVE System". IEEE Multimedia, 3(1), 30-39, 1996
[3] John K. Ousterhout, "Tcl and the Tk toolkit", Addison-Wesley Publishing Co., 1994
[4] Emmanuel Frécon and Olof Hagsand, "The Dive/Tcl Behaviour Interface", Reference Document, available at
<http://www.sics.se/dive/manual/tcl-behaviour.html>
[5] Sun Microsystems, "Java Home Page", available at <http://java.sun.com/ >