Writing your first C module
The AOLServer C API is very easy to develop towards. This short tutorial takes you through construction of an "nshello" module that provides a "ns_hello" function.
Step 0: Requirements
You need (at least) ns.h and Makefile.module.
On Debian, simply:
apt-get install aolserver4-dev
Step 1: Write your module code, "nshello.c" (this can be any name you like):
/*
* Get the data types and constants you will need later on,
* such as Tcl_Interp and NS_OK.
*/
#include "ns.h"
#include <string.h>
#include <sys/types.h>
/*
* Each module asserts its version via the required Ns_ModuleVersion variable
*/
int Ns_ModuleVersion = 1;
/*
* Declare that this module will implement this initialization method.
*/
int Ns_ModuleInit(char *hServer, char *hModule);
/*
* This can be named whatever you like, it is used during module initialisation
* to contain specific initialisation steps for the Tcl interpreter itself,
* such as registering commands like "ns_hello".
*/
static int HelloInterpInit(Tcl_Interp *interp, void *context);
/*
* Declare a C function that will be bound to the "ns_hello" Tcl command.
*/
static int HelloCmd(ClientData context, Tcl_Interp *interp, int argc, char **argv);
/*
* Implement the Ns_ModuleInit function we declared we would implement earlier.
* This is called by the server right after the module is loaded. Here, you
* can read configuration data, initialise internal data, and of course
* register any Tcl commands.
*/
int Ns_ModuleInit(char *hServer, char *hModule)
{
/*
* Invoke the server's Tcl interpreter initialisation and pass
* it the callback we defined to our own interpreter initialisation.
*/
return (Ns_TclInitInterps(hServer, HelloInterpInit, NULL));
}
/*
* Implement the interpreter initialisation we declared and passed
* during module init. Use Tcl_CreateCommand to register
* the command "ns_hello", passing a callback to "HelloCmd" which
* we declared earlier.
*/
static int HelloInterpInit(Tcl_Interp *interp, void *context)
{
Tcl_CreateCommand(interp, "ns_hello", HelloCmd, NULL, NULL);
return NS_OK;
}
/*
* Append "hello" and then all arguments to the result.
*/
static int HelloCmd(ClientData context, Tcl_Interp *interp, int argc, char **argv)
{
int i;
Tcl_AppendResult(interp, "hello", NULL);
for (i = 0; i < argc; i++)
{
Tcl_AppendResult(interp, " ", NULL);
Tcl_AppendResult(interp, argv[i], NULL);
}
return NS_OK;
}
That's it. That's an entire module.
Step 2: Build your module.
AOLServer includes a meta-Makefile Makefile.module that simplifies the construction of module makefiles. Simply define a few values in your owm Makefile, then include this meta-Makefile.
# # Module name # MOD = nshello.so # # Objects to build # OBJS = nshello.o # # Header files in THIS directory # HDRS = # # Extra libraries # MODLIBS = # # Compiler flags # CFLAGS = include /usr/lib/aolserver4/Makefile.module
Done. Now you can build your module with 'make'.
You should now have a nifty "nshello.so" shared object library sitting around. Copy "nshello.so" to /usr/lib/aolserver4/bin (or where you keep your server modules).
Step 3: Tell aolserver to load the module (/etc/aolserver4/aolserver4.tcl):
ns_section "ns/server/${servername}/modules"
ns_param nshello nshello.so
Done. Restart aolserver and check the log file for errors.
Step 4: Use the function "ns_hello" in an ADP script:
<% ns_adp_puts [ns_hello "AOLServer module" "world!"] %>
Whoa! You get a strange result: hello ns_hello AOLServer module world!
Notice that "ns_hello" in there? That's because argv[0] is actually the name of the function used to call your interpreter! So, keep that in mind and happy AOLServer module hacking!