$Header: /cvsroot/aolserver/aolserver.com/docs/devel/c/c-examples.html,v 1.1 2002/03/07 19:15:35 kriston Exp $
Example 1: nshello
The following example provides a single request function which handles
the /helloworld URL, returning 'Hello'. This module is the simplest of
the AOLserver example modules.
#include "ns.h"
/*
* This is the simplest possible example of adding a C module
* to the AOLserver.
*/
/*
* The Ns_ModuleVersion exported integer is used to verify
* this module version when loaded. For AOLserver 2.0,
* 1 (one) is the only valid value for this variable.
*/
int Ns_ModuleVersion = 1;
static Ns_OpProc Hello;
/*
* The Ns_ModuleInit function is the function the AOLserver
* will call each time the module is loaded into a
* server. The function is passed two parameters:
*
* hServer: The server `handle' as a string. This is the
* short name given to the virutal server such
* as `server1'.
*
* hModule: The module `handle' as a string. This is the
* short name given to the module such as `hello'
*
* For example, if this module is known as `hello' and loaded
* into the `server1' server with entries similar to the following
* in the nsd.ini file:
*
* [ns\servers]
* server1=My First Server
*
* [ns\server1\modules]
* hello=hello.dll ; or hello.so on Unix platforms
*
* This function would be called with "server1" and "hello" as
* its arguments.
*
*/
int
Ns_ModuleInit(char *hServer, char *hModule)
{
Ns_RegisterRequest(hServer, "GET", "/helloworld", Hello,
NULL, NULL, 0);
return NS_OK;
}
static int
Hello(Ns_OpContext context, Ns_Conn *conn)
{
char html[]="Hello World.";
Ns_ConnReturnHtml(conn, 200, html, strlen(html));
return NS_OK;
}
Example 2: alias
The following example is an Url-to-file translation module which
converts a virtual URL to a physical pathname. This module is much
more flexible than the translation routine built into the AOLserver
and allows you to map multiple URL prefixes to different physical
directories. This has been an often requested feature and the alias
module will be the default translation routine in a future release.
/*
* This example module implements a URL->file aliasing extension to the
* AOLserver using the Ns_SetUrlToFileProc function from the C API. Loading
* this module enables you to define mappings such as
* /oldplace/foo.html=newplace/foo.html. This module maintains compatibility
* with the existing (default) AOLserver UrlToFile function by supporting
* UserMapDir and PageRoot configuration variables, both of which are
* subsumed by the expressive capabilities of this module.
*
* You can load and configure this module by editing your nsd.ini file as
* follows:
* 1) In your [ns\server\server-name\modules] section, add the
* following:
* alias=alias.dll ;or alias.so on Unix platforms
* 2) Add a section for the alias module that contains your aliases. E.g.:
* [ns\server\server-name\module\alias]
* /oldplace/foo.html=newplace/foo.html
* ...
*
* Note that you can accomplish the above with the setup interface by using the
* "List AOLserver Configuration Sections" available from the "Setup Home"
* page in expert mode, or you can edit the nsd.ini file with your favorite
* text editor.
*
* When defining maps with key/value pairs, keep the following in mind:
* 1) The key (`/oldplace/foo.html' above) is in "URI space" and the value
* (`newplace/foo.html' above) is in "file space".
* 2) By default, the file space value (`newplace/foo.html' above) is assumed
* to be relative to the page root defined for the "server-name"
* server. In "file space" (right side of =), you can also
* specify an absolute pathname such as /home/user/html/index.html.
* So, be careful not to use a leading `/'
* on the right side of the `=' unless you mean it.
* 3) In "file space", `~username' expands to the user's default directory, and
* `~' looks for a user name in the second element of the URI, substituting
* the user's home directory appropriately.
* 4) In "URI space", a leading `/~' mapped to a leading `~' in file spacesupports
* the common ~user usage in URI space.
*
* Now, let's clear things up with an example. Note that the comments following each
* mapping show a sample URI input followed by sample output generated by this module.
* [ns\server\server-name\module\alias]
* /user1=~godzilla ;/user1 -> /home/godzilla
* /user2=~/pages ;/user2/bambi -> /home/bambi/pages
* ;OR /user2/bambi/foo -> /home/bambi/pages/foo
* /user3=~ ;/user3/bambi -> /home/bambi
* ;OR /user3/bambi/html -> /home/bambi/html
* /~=~/pages ;/~foot -> /home/foot/pages
* ;OR /~foot/section -> /home/foot/pages/section
*
* Note that the last entry obviates the need for the `UserMapDir' configuration
* parameter. To provide compatibility with the default Ns_UrlToFile function, we'll
* insert a mapping to reflect the UserMapDir if it is set in the nsd.ini file.
* If UserMapDir is defined and there is a mapping of the form: /~=~/otherplace,
* the mapping takes precedence.
*
* Another mapping, more pervasive than the previous examples, is the following:
* /=/home/newroot
* This overrides the PageRoot parameter defined in the server-specific section
* of nsd.ini. As you would expect, it also defines the implicit root forall other
* relative "file space" (right side of `=') values that appear in other aliases.
*
*/
#include "ns.h"
#include
#include
#define MAPMETHOD "GET" /* placeholder in the general-purpose URL-space routines */
/* The following string is appended to user directories (for compatibility) */
#define CONFIG_USERMAPDIR "UserMapDir"
#define MAX_USERNAME 16
/*
* This data will be made available to our custom UrlToFile function
* (AliasedUrlToFile)
*/
typedef struct {
char *fromUri;
char *toUri;
} UriMap;
static Ns_UrlToFileProc AliasedUrlToFile;
static void UriMapFree(UriMap * map);
static int TildeReplace(char *hServer, Ns_DString * dsOut, char *in, char *uri);
static UriMap *NewMap(char *from, char *to);
/*
* The Ns_ModuleVersion exported integer is used to verify this module
* version when loaded. For AOLserver 2.0, 1 (one) is the only valid value
* for this variable.
*/
int Ns_ModuleVersion = 1;
/*
* The following are global IDs used for server-specific storage and
* retrieval of data
*/
static int idAliases = -1;
/*
* The Ns_ModuleInit function is the function the AOLserver will call each
* time the module is loaded into a server. The function is passed
* two parameters:
*
* hServer: The server `handle' as a string. This is the short name given to
* the virutal server such as `server1'.
*
* hModule: The module `handle' as a string. This is the short name given to
* the module such as `alias'
*
* For example, if this module is known as `alias' and loaded into the `server1'
* server with entries similar to the following in the nsd.ini file:
*
* [ns\servers]
* server1=My First Server
*
* [ns\server1\modules]
* alias=alias.dll
*
* This function would be called with "server1" and "alias" as its arguments.
*
*/
int
Ns_ModuleInit(char *hServer, char *hModule)
{
char *moduleConfigPath;
char *serverConfigPath;
char *userMapDir;
Ns_Set *aliases;
int i;
if (idAliases < 0) {
idAliases = Ns_ServerSpecificAlloc();
}
serverConfigPath = Ns_ConfigGetPath(hServer, NULL, NULL);
/*
* for compatibility with the default UrlToFile, create entry forUserMapDir
* if it is defined
*/
if ((userMapDir = Ns_ConfigGetValue(serverConfigPath, CONFIG_USERMAPDIR)) !=
NULL) {
UriMap *map;
Ns_DString dsFilePattern;
Ns_DStringInit(&dsFilePattern);
Ns_DStringVarAppend(&dsFilePattern, "~/", userMapDir, NULL);
map = NewMap("/~", Ns_DStringExport(&dsFilePattern));
Ns_Log(Notice, "Ns_ModuleInit(%s,%s): Mapping %s to %s", hServer, hModule,
map->fromUri, map->toUri);
Ns_UrlSpecificSet(hServer, MAPMETHOD, map->fromUri, idAliases,
map, 0, (void (*) (void *)) UriMapFree);
}
if ((moduleConfigPath = Ns_ConfigGetPath(hServer, hModule, NULL)) == NULL) {
Ns_Log(Warning,
"Ns_ModuleInit(%s,%s): No file aliases section found in config file",
hServer, hModule);
} else {
if ((aliases = Ns_ConfigGetSection(moduleConfigPath)) != NULL) {
if (Ns_SetSize(aliases) > 0) {
Ns_DString dsNormalizedKey;
Ns_DStringInit(&dsNormalizedKey);
/*
* The following function causes the
* AOLserver to call our AliasedUrlToFile
* function instead of its default when
* mapping a URI to a filename.
*/
Ns_SetUrlToFileProc(hServer, AliasedUrlToFile);
for (i = 0; i < Ns_SetSize(aliases); ++i) {
UriMap *map;
char *value;
/*
* Normalize the path so that we can
* use it for matching in
* AliasedUrlToFile
*/
Ns_NormalizePath(&dsNormalizedKey, Ns_SetKey(aliases, i));
value = Ns_SetValue(aliases, i);
if ((strncmp(dsNormalizedKey.string, "/~",2)==0) &&
(value[0] != `~')) {
Ns_Log(Warning,
"AliasedUrlToFile(%s): %s->%s ignored, %s must start with `~'",
hServer, dsNormalizedKey.string, value, value);
} else {
map = NewMap(ns_strdup(dsNormalizedKey.string),
ns_strdup(value));
Ns_Log(Notice, "Ns_ModuleInit(%s,%s): Mapping %s to %s",
hServer, hModule, map->fromUri, map->toUri);
Ns_UrlSpecificSet(hServer,MAPMETHOD, map->fromUri,
idAliases, map,0, (void (*) (void *)) UriMapFree);
}
Ns_DStringTrunc(&dsNormalizedKey, 0);
}
Ns_DStringFree(&dsNormalizedKey);
}
}
}
return NS_OK;
}
/*
* This function, registered above via Ns_SetUrlToFileProc, will be calledby
* the AOLserver when it maps a URL to a file.
*/
static int
AliasedUrlToFile(Ns_DString * dest, char *hServer, char *relpath)
{
int retval = NS_OK;
Ns_DString dsAliasedPath;
UriMap *map;
assert(relpath != NULL);
assert(dest != NULL);
Ns_DStringInit(&dsAliasedPath);
/* special handling of `/~' pattern in URI */
if (relpath[0]=='/' && relpath[1]=='~') {
if ((map = Ns_UrlSpecificGet(hServer, MAPMETHOD, "/~", idAliases))== NULL) {
Ns_Log(Error, "AliasedUrlToFile(%s): URI %s has not been aliased",
hServer, relpath);
retval = NS_ERROR;
} else if (map->toUri[0]=='~') {
retval = TildeReplace(hServer, &dsAliasedPath, map->toUri, relpath);
} else {
Ns_Log(Bug,
"AliasedUrlToFile(%s): In mapping %s->%s, %s must contain a `~'",
hServer, map->fromUri, map->toUri, map->toUri);
retval = NS_ERROR;
}
} else {
/*
* Check whether the URI (relpath) has been registered for
* aliasing...
*/
if ((map = Ns_UrlSpecificGet(hServer, MAPMETHOD, relpath, idAliases))
== NULL) {
/* no match, copy relpath to destination */
Ns_DStringAppend(&dsAliasedPath, relpath);
} else {
/* matched, check for `~', exact match or initial subpath match of file
pattern*/
int relpathLen, fromUriLen;
if (map->toUri[0] == `~') {
retval = TildeReplace(hServer, &dsAliasedPath, map->toUri,relpath);
} else {
fromUriLen = strlen(map->fromUri);
relpathLen = strlen(relpath);
if (fromUriLen == relpathLen) {
/* exact match, use simple substitution */
Ns_DStringAppend(&dsAliasedPath, map->toUri);
} else if (fromUriLen < relpathLen) {
/*
* initial subpath match, substitute only for length
* of map->fromUri
*/
Ns_DStringVarAppend(&dsAliasedPath, map->toUri,
relpath[fromUriLen]=='/' ? "" : "/",
&relpath[fromUriLen], NULL);
} else {
Ns_Log(Error, "AliasedUrlToFile(%s): %s to %s mapping is not valid",
hServer, map->fromUri, relpath);
retval = NS_ERROR;
}
}
}
}
if (retval == NS_OK) {
if (Ns_PathIsAbsolute(dsAliasedPath.string) && (map != NULL)) {
Ns_MakePath(dest, dsAliasedPath.string, NULL);
} else { /* relative path, use pageroot or / from URI space */
UriMap *map;
char *root;
/* URI `/' takes precedence over pageroot */
if ((map = Ns_UrlSpecificGet(hServer, MAPMETHOD, "/", idAliases))
== NULL) {
root = Ns_PageRoot(hServer);
} else {
root = map->toUri;
}
Ns_MakePath(dest, root, dsAliasedPath.string, NULL);
}
}
Ns_DStringFree(&dsAliasedPath);
return retval;
}
/*
* This function performs the expansion and substitution related to
* the `~' character as it appears in the URI and file patterns
* defined in the nsd.ini file, and in the URI input. In this function,
* remember that `filePattern' is the string that appeared on the right
* side of the `=' in the nsd.ini file and `uri' is the URI from our current
* request, not to be confused with the URI (left of `=') defined in the
* nsd.ini file which is used for pattern matching.
*
*/
static int
TildeReplace(char *hServer, Ns_DString * dsOut, char *filePattern, char *uri)
{
int retval = NS_OK;
char *pathRemainder;
char *nameEnd;
char *uriTail = `\0';
int found;
char user[MAX_USERNAME+1];
int len;
assert (filePattern[0] == `~');
if (filePattern[1] == `\0' || filePattern[1] == `/') { /*~ or ~/ in filePattern */
char *nameStart;
/* parse out user name, second element in uri OR string following /~ */
if (strncmp(uri, "/~", 2) == 0) { /* special case mapping of /~* = ~ */
nameStart = &uri[2];
if (*nameStart == `\0') {
nameStart = NULL;
}
} else {
/* skip past first element */
if ((nameStart = strchr(&uri[1], `/')) != NULL) {
++nameStart;
}
}
if (nameStart == NULL) {
Ns_Log(Error,
"AliasedUrlToFile:TildeReplace(%s): user name not found in URI: %s",
hServer, uri);
retval = NS_ERROR;
} else {
uriTail = strchr(nameStart, `/');
len = (uriTail==NULL) ? strlen(nameStart) : uriTail - nameStart;
if (len >= sizeof(user)) {
Ns_Log(Warning,
"AliasedUrlToFile:TildeReplace(%s): URI User name too long",
hServer);
retval = NS_ERROR;
} else {
strncpy(user, nameStart, len);
user[len] = `\0';
found = Ns_GetUserHome(dsOut, user);
pathRemainder = (filePattern[1]=='\0') ? "" : &filePattern[1];
}
}
} else {
uriTail = strchr(&uri[1], `/'); /* skip past substituted field in URI */
if ((nameEnd = strchr(&filePattern[1], `/')) == NULL) { /* ~user */
found = Ns_GetUserHome(dsOut, &filePattern[1]);
pathRemainder = "";
} else { /* ~user/more/stuff */
len = nameEnd - filePattern - 1;
if (len >= sizeof(user)) {
Ns_Log(Warning,
"AliasedUrlToFile:TildeReplace(%s): Mapped User name too long",
hServer);
retval = NS_ERROR;
} else {
strncpy(user, &filePattern[1], len);
user[len] = `\0';
found = Ns_GetUserHome(dsOut, user);
pathRemainder = nameEnd;
}
}
}
if (retval == NS_OK) {
if (!found) {
Ns_Log(Warning, "AliasedUrlToFile:TildeReplace(%s): Unknown user",
hServer);
retval = NS_ERROR;
} else {
Ns_DStringAppend(dsOut, pathRemainder);
if (uriTail != NULL) {
Ns_DStringAppend(dsOut, uriTail);
}
}
}
return retval;
}
static UriMap *
NewMap(char *from, char *to)
{
UriMap *map;
map = ns_malloc(sizeof(UriMap));
map->fromUri = from;
map->toUri = to;
return map;
}
static void
UriMapFree(UriMap * map)
{
ns_free(map->fromUri);
ns_free(map->toUri);
ns_free(map);
}
Example 3: counter
The following example implements a request function that generates the
popular odometer-like page count image. The code is based on the
popular odometer.c CGI program available at many archive sites, but
because it's loaded directly into the AOLserver it generates the
odometer at lightening speed, easily 10x faster!
/*-
*
* This code implements an odometer-like page counter extension to the
* AOLserver. The code is based on the popular "odometer" CGI
* by Chris Stephens, stephenc@pcmail.cbil.vcu.edu, and
* Fred Christiansen, fredch@fc.hp.com (see below).
*
* Why use this module instead of the CGI? By loading the code directly
* into the AOLserver, you avoid all the painful overhead of CGI.
* The result is this module is more than 10 times as fast as the CGI!
* Plus, it compiles and run on all platforms!
*
* To use the counter, load the module and insert an image
* link of the form
.
* The NsCounter() function will return a small odometer image of the
* number of hits to the corresponding page (i.e., /my/page.htm). The
* page count is kept in a file prefixed by .odo (i.e., /my/.odo.page.htm).
*
* To load this module, add the following to the [ns\server\\modules]
* section of your nsd.ini file where is the name of the
* server you want to add the counter too:
*
* counter=counter.dll ; or counter.so on Unix platforms
*
* This prefix(s) of the count URL can be set with the "UrlPrefix"
* key in the module's nsd.ini configuration file section (i.e.,
* [ns\server\\module\counter]). The value is a comma separated
* list of URL prefixes. For example, if the list includes the
* "/cnt,/count" prefixes, then any URL which begins with /cnt or
* /count will be processed by the NsCounter() function.
*
* Note: the setup interface in AOLserver 2.0 is open-ended, so you can
* use it to view/edit these parameters by using the "List AOLserver
* Configuration Sections" available from the "Setup Home" page in expert
* mode
*
*/
#include "ns.h"
#include
#include
#include
#ifdef WIN32
#include
#include
#else
#include
#endif
#define CONFIG_PREFIX "UrlPrefix"
#define DEFAULT_PREFIX "/cgi-bin/counter,/NS/Counter,/ns/counter"
#define COUNT_PREFIX ".odo"
static Ns_OpProc NsCounter;
int Ns_ModuleVersion = 1;
int
Ns_ModuleInit(char *hServer, char *hModule)
{
char *configPath;
char *urlPrefix;
char *next;
Ns_DString dsBuf;
Ns_DString dsPath;
/*
* Fetch the UrlPrefix from the config file.
*/
configPath = Ns_ConfigGetPath(hServer, hModule, NULL);
urlPrefix = Ns_ConfigGetValue(configPath, CONFIG_PREFIX);
if (urlPrefix == NULL) {
urlPrefix = DEFAULT_PREFIX;
}
/*
* Register NsCounter at each of the URL's specified
* in the comma seperated UrlPrefix list.
*/
Ns_DStringInit(&dsBuf);
Ns_DStringInit(&dsPath);
Ns_DStringAppend(&dsBuf, urlPrefix);
next = dsBuf.string;
do {
urlPrefix = next;
next = strchr(urlPrefix, `,');
if (next != NULL) {
*next++ = `\0';
}
if (*urlPrefix != `/') {
Ns_Log(Warning, "%s(%s): Invalid URL prefix skipped: %s",
hModule, hServer, urlPrefix);
} else {
Ns_NormalizePath(&dsPath, urlPrefix);
urlPrefix = Ns_DStringExport(&dsPath);
Ns_RegisterRequest(hServer, "GET", urlPrefix, NsCounter, ns_free,
urlPrefix, 0);
}
} while (next != NULL);
Ns_DStringFree(&dsBuf);
Ns_DStringFree(&dsPath);
return NS_OK;
}
/*-
** Originally count.c, by Chris Stephens, stephenc@pcmail.cbil.vcu.edu, (c)1995.
** Code cleaned up and enhanced by Fred Christiansen, fredch@fc.hp.com,
** as odometer.c; supports:
** - 8 digits instead of 7 (and by changing ODO_DIGITS, up to 10 (number
** of digits in an unsigned long))
*/
#define NL `\n' /* new line char */
#define ODO_DIGITS 8 /* # digits displayed */
#define BUFSIZE (ODO_DIGITS+2) /* 8 digits + NL + nul */
#define BM_HT 16 /* bitmap height */
#define BM_WD 8 /* bitmap width */
static char *bitmap[] = {
"0xff", "0xff", "0xff", "0xc3", "0x99", "0x99", "0x99", "0x99", /* rows 1-8 of 0 */
"0x99", "0x99", "0x99", "0x99", "0xc3", "0xff", "0xff", "0xff", /* rows 9-16 of 0 */
"0xff", "0xff", "0xff", "0xcf", "0xc7", "0xcf", "0xcf", "0xcf", /* rows 1-8 of 1 */
"0xcf", "0xcf", "0xcf", "0xcf", "0xcf", "0xff", "0xff", "0xff", /* rows 9-16 of 1 */
"0xff", "0xff", "0xff", "0xc3", "0x99", "0x9f", "0x9f", "0xcf", /* rows 1-8 of 2 */
"0xe7", "0xf3", "0xf9", "0xf9", "0x81", "0xff", "0xff", "0xff", /* rows 9-16 of 2 */
"0xff", "0xff", "0xff", "0xc3", "0x99", "0x9f", "0x9f", "0xc7", /* rows 1-8 of 3 */
"0x9f", "0x9f", "0x9f", "0x99", "0xc3", "0xff", "0xff", "0xff", /* rows 9-16 of 3 */
"0xff", "0xff", "0xff", "0xcf", "0xcf", "0xc7", "0xc7", "0xcb", /* rows 1-8 of 4 */
"0xcb", "0xcd", "0x81", "0xcf", "0x87", "0xff", "0xff", "0xff", /* rows 9-16 of 4 */
"0xff", "0xff", "0xff", "0x81", "0xf9", "0xf9", "0xf9", "0xc1", /* rows 1-8 of 5 */
"0x9f", "0x9f", "0x9f", "0x99", "0xc3", "0xff", "0xff", "0xff", /* rows 9-16 of 5 */
"0xff", "0xff", "0xff", "0xc7", "0xf3", "0xf9", "0xf9", "0xc1", /* rows 1-8 of 6 */
"0x99", "0x99", "0x99", "0x99", "0xc3", "0xff", "0xff", "0xff", /* rows 9-16 of 6 */
"0xff", "0xff", "0xff", "0x81", "0x99", "0x9f", "0x9f", "0xcf", /* rows 1-8 of 7 */
"0xcf", "0xe7", "0xe7", "0xf3", "0xf3", "0xff", "0xff", "0xff", /* rows 9-16 of 7 */
"0xff", "0xff", "0xff", "0xc3", "0x99", "0x99", "0x99", "0xc3", /* rows 1-8 of 8 */
"0x99", "0x99", "0x99", "0x99", "0xc3", "0xff", "0xff", "0xff", /* rows 9-16 of 8 */
"0xff", "0xff", "0xff", "0xc3", "0x99", "0x99", "0x99", "0x99", /* rows 1-8 of 9 */
"0x83", "0x9f", "0x9f", "0xcf", "0xe3", "0xff", "0xff", "0xff" /* rows 9-16 of 9 */
};
/*
* NsCounter -
*
* Handle a request of the form "/NS/Counter/my/page.htm" to create an
* odometer-like count of visits to the /my/page.htm page.
*
*/
static int
NsCounter(void *context, Ns_Conn *conn)
{
char buf[BUFSIZE], dial[ODO_DIGITS];
unsigned long cnt;
int status, i, l;
char *p;
Ns_DString ds;
int fd;
char *uri;
char *hServer;
char *urlPrefix;
int nPrefix;
hServer = Ns_ConnServer(conn);
urlPrefix = (char *) context;
/*
* Figure out how many parts are in the
* prefix, i.e., /NS/Counter has 2 parts.
*/
nPrefix = 0;
p = urlPrefix;
while ((p = strchr(p, `/')) != NULL) {
++p;
++nPrefix;
}
if (conn->request->urlc > nPrefix) {
uri = Ns_SkipUrl(conn->request, nPrefix);
} else {
return Ns_ConnReturnBadRequest(conn, "Missing URI");
}
/*
* Convert the URI to the file, sneaking in counter prefix before the last
* path element.
*/
Ns_DStringInit(&ds);
p = strrchr(uri, `/');
*p = `\0';
Ns_UrlToFile(&ds, hServer, uri);
Ns_DStringAppend(&ds, "/");
Ns_DStringAppend(&ds, COUNT_PREFIX);
*p++ = `/';
Ns_DStringAppend(&ds, ".");
Ns_DStringAppend(&ds, p);
/*
* Open (or create) the counter file and increment the page count.
*/
fd = open(ds.string, O_RDWR | O_CREAT, 0660);
if (fd < 0) {
Ns_Log(Error, "Could not open counter file `%s' for URI `%s': %s",
ds.string, uri, strerror(errno));
Ns_DStringFree(&ds);
return Ns_ConnReturnInternalError(conn);
}
Ns_DStringFree(&ds);
i = read(fd, buf, BUFSIZE);
if (i > 0) {
buf[i] = `\0';
cnt = strtoul(buf, (char **) NULL, 10);
} else {
cnt = 0;
}
lseek(fd, 0, SEEK_SET);
sprintf(buf, "%u\n", ++cnt);
write(fd, buf, strlen(buf));
close(fd);
/* Calc length (ignoring NL) and copy right-to-left into dial */
for (l = 0, p = buf; *p != `\0' && *p != NL; l++, p++);
for (i = 0, p = buf; i < l; i++, p++)
dial[ODO_DIGITS - l + i] = *p;
for (i = 0; i < (ODO_DIGITS - l); i++) /* backfill with zeros */
dial[i] = `0';
/*
* Build up the odometer xbm.
*/
Ns_DStringPrintf(&ds, "#define odo_width %d\n", (BM_WD * ODO_DIGITS));
Ns_DStringPrintf(&ds, "#define odo_height %d\n", BM_HT);
Ns_DStringAppend(&ds, "static char odo_bits[] = {\n");
for (i = 0; i < BM_HT; i++) {
for (l = 0; l < ODO_DIGITS; l++) {
Ns_DStringAppend(&ds, bitmap[(((dial[l] - `0') * BM_HT) + i)]);
Ns_DStringAppend(&ds, ", ");
if (l == 7)
Ns_DStringAppend(&ds, "\n");
}
if (i == 15) {
Ns_DStringAppend(&ds, "};");
}
}
Ns_DStringAppend(&ds, "\n");
/*
* Setup the HTTP headers.
*/
Ns_ConnSetRequiredHeaders(conn, "image/x-xbitmap", ds.length);
status = Ns_ConnFlushHeaders(conn, 200);
if (status == NS_OK) {
/*
* Send the bitmap if the headers were sent o.k.
*
* Note that the underlying communications driver may send
* less than the number of bytes requested so we need to
* call Ns_ConnWrite() in a while loop to ensure all the
* bytes are sent. If the connection is shut down while
* attempting to send, the communication driver returns
* -1 and we set status to NS_ERROR and immediately break
* out of the loop. Whenever a status other than NS_OK
* is returned from a request function, the AOLserver does
* not run the registered trace functions (trace functions
* are normally used for access logging and you shouldn't
* normally log aborted connections).
*
* Actually, in this trivial case, you could simply use:
*
* status = Ns_ConnPuts(conn, ds.string)
*
* which pretty much implements the loop below.
*/
p = ds.string;
i = ds.length;
while (i > 0) {
cnt = Ns_ConnWrite(conn, p, i);
if (cnt < 0) {
status = NS_ERROR;
break;
}
i -= cnt;
p += cnt;
}
}
Ns_DStringFree(&ds);
return status;
}
Example 4: stats
The following example provides several cooperating facilities to
implement a simple connection statistics system. The module includes a
trace to collect the statistics on each connection, a scheduled
procedure to aggregate the statistics, the /NS/Stat request function
to print the statistics, and a Tcl command to access the statistics in
a script.
/*
* stat.c - Example C module.
*
* This example incorporates many of the features of the AOLserver
* C API in a single simple, but useful, statistics gathering module.
* The module maitains statistics on the number of connections and
* bytes sent by a server. The data is stored in a simple
* `StatContext' structure which is allocated when the module is
* loaded. The StatContext stores the current, last, and total numbers
* and is updated after each connection by the `StatTrace' connection
* trace procedure. At a regular interval (the interval in seconds
* is configurable), the `StatUpdate' funcation is called to log the
* current and total number to the AOLserver log file and then
* makes the current data the last data. Access to these data is
* provided in two forms:
*
* 1. A simple C request function, `StatRequest', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in the ServerContext structure ', will return the
* current data as a simple notice page. The StatRequest function
* is registered at the GET /NS/Stat URL of the server.
*
* 2. The `ns_stat' Tcl command is added to each Tcl interpreter
* of the server interpreter pool. This allows a Tcl script
* to access the current, last, or total data at any time.
*
* Because the AOLserver is completely multithreaded, the statistics
* data can be updated and queried simultaneously. An Ns_Mutex is
* included in th