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.
NOTE: This has been updated for aolserver4.5 (ns.mak) --Caveman 15:49, 8 October 2009 (EDT)
Step 0: Requirements
You need (at least) ns.h and ns.mak.
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. It can be * named whatever you like as well. */ 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 # # Objects to build # .o will be matched to .c files # OBJS = nshello.o # # Header files in THIS directory # HDRS = # # Extra libraries # MODLIBS = # # Compiler flags # CFLAGS = include /usr/share/aolserver4/ns.mk
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!
Continued Topics
Calling Tcl from within your module (i.e. call ns_rand from your module).
Reading configuration sections during initialisation.
Linking to other C libraries in the build process (e.g. linking with libpng).