/******************************************************************************* * * Copyright (c) 2000, Tortuga Technologies Pty Ltd. All rights reserved. * * This is unpublished proprietary source code of Tortuga Technologies. * The copyright notice above does not evidence any actual or intended * publication of such source code. * ******************************************************************************* * * Filename: $Id: example.c,v 1.1 2002/04/22 10:11:23 jill Exp $ * * Description: Example injun application and timeout stress tester * * History * ------- * $Log: example.c,v $ * Revision 1.1 2002/04/22 10:11:23 jill * Initial import * * Revision 1.1.1.1 2000/02/18 06:41:30 graham * initial import * ******************************************************************************/ /* standard includes */ #include "machdeps.h" #include #include #include #include #include /* local includes */ #include "log.h" #include "injun.h" /****************************************************************************** * * Minimum and maximum values of the configurable variables * ******************************************************************************/ #define MIN_TIMEOUT 1 #define DEF_TIMEOUT 5000 #define MAX_TIMEOUT 2147483647 #define MIN_LOGTIME 1 #define DEF_LOGTIME 3600 #define MAX_LOGTIME 2147483647 #define MIN_OFFSET 0 #define DEF_OFFSET 1 #define MAX_OFFSET 1000 /****************************************************************************** * * Logging id for log functions * ******************************************************************************/ static int lid; /****************************************************************************** * * Number of timeouts and mutex protection * ******************************************************************************/ static pthread_mutex_t mx; static unsigned int number = 0; /****************************************************************************** * * Configurable variables and their last value * ******************************************************************************/ static unsigned int interval = DEF_TIMEOUT; static unsigned int offset = DEF_OFFSET; static unsigned int logtime = DEF_LOGTIME; static unsigned int old_interval= DEF_TIMEOUT; static unsigned int old_offset = DEF_OFFSET; static unsigned int old_logtime = DEF_LOGTIME; /****************************************************************************** * * Stylesheet shared between all web pages * ******************************************************************************/ static char example_stylesheet[] = { "BODY {\n" " font-family: \"helvetica\", \"arial\";\n" " background: #008B8B\n" "}\n\n" "H1 {\n" " font-family: \"helvetica\", \"arial\";\n" " text-align: center\n" "}\n\n" "TABLE {\n" " text-align: center\n" "}\n\n" "TD {\n" " font-family: \"helvetica\", \"arial\";\n" " font-weight: normal;\n" " font-style: normal\n" "}\n\n" "TH {\n" " font-family: \"helvetica\", \"arial\";\n" " font-weight: bold;\n" " font-style: normal\n" "}\n\n" "INPUT {\n" " font-family: \"helvetica\", \"arial\";\n" " font-weight: bold;\n" " font-size: 14pt;\n" " color: red\n" "}\n\n" }; /****************************************************************************** * * Timeout identification parameter * ******************************************************************************/ static char *timeout = "timeout"; /****************************************************************************** * * Local prototypes * ******************************************************************************/ static int example_make_page( char *body, char *title, char *style, char **page ); static void example_status( web_page_t *page, struct webcb_args_s *args ); static void example_timeout( void *args ); static void example_config( web_page_t *page, struct webcb_args_s *args ); static void serve_config_page( int fd ); /****************************************************************************** * * Global exported prototypes and parameters * ******************************************************************************/ int example_init( int argc, char *argv[] ); int example_dele( int argc, char *argv[] ); char example_version[SMLBUF] = "@(#) 1.0.0"; /*ARGSUSED*/ /******************************************************************************* * * Unit: example_init() * * Description: initialises the example application in the injun environment * * Notes: * * Parameters: argc/argv in standard format (NULL in this app) * * Globals: * * Returns: OK - the application was loaded and initialised * FAIL - something went wrong, we cleaned up and quit out * ******************************************************************************/ int example_init( int argc, char *argv[] ) { int status; char *index = NULL; /* finished web page */ char *body = "
\n" "

Example Index Page

\n" "
\n" "\n" "\n" "\n" "\n" "
\n" "This page is a static web page which has been created by " "the example application and then loaded into the \n" "Injun web server. In the table below you will " "see a link to a page which will be created on the \n" "fly as it is served to your browser ! \n" "
Dynamic Web Page
Timeout Configuration
\n"; /* initialise the logging for this code */ log_next_id( "example", &lid ); /* create a mutex to protect critical data */ status = pthread_mutex_init( &mx, NULL ); if ( status != OK ) { log( lid, LOG, "_init: failed to initialise mutex" ); return( FAIL ); } /* setup a regular timeout */ status = injun_add_timeout( 5000, (void *)example_timeout, (void *)timeout ); if ( status != OK ) { log( lid, LOG, "_init: failed to add initial timeout" ); (void) pthread_mutex_destroy( &mx ); return( FAIL ); } /* we will use the default tree provided by injun */ status = injun_add_page( "/example/example.css", "text/css", strlen(example_stylesheet), example_stylesheet, PT_STATIC, NULL ); if ( status != OK ) { log( lid, LOG, "_init: failed to add stylesheet to tree" ); (void) pthread_mutex_destroy( &mx ); return( FAIL ); } /* create the web page with the head and footer routines */ status = example_make_page( body, "Example Index Page", "/example/example.css", &index ); if ( status != OK ) { log( lid, LOG, "_init: failed to create web page" ); (void) pthread_mutex_destroy( &mx ); (void) injun_remove_page( "/example/example.css" ); return( FAIL ); } /* we will use the default tree provided by injun */ status = injun_add_page( "/example/index.html", "text/html", strlen(index), index, PT_DYNAMIC, NULL ); if ( status != OK ) { log( lid, LOG, "_init: failed to add home page to tree" ); (void) pthread_mutex_destroy( &mx ); (void) injun_remove_page( "/example/example.css" ); free( index ); return( FAIL ); } /* add the example routine() to the tree */ status = injun_add_page( "/example/status.html", NULL, 0, NULL, PT_FUNCTION, (void *)example_status ); if ( status != OK ) { log( lid, LOG, "_init: failed to add \"status\" callback to tree" ); (void) pthread_mutex_destroy( &mx ); (void) injun_remove_page( "/example/example.css" ); (void) injun_remove_page( "/example/index.html" ); return( FAIL ); } /* add the example timeout configuration routine() to the tree */ status = injun_add_page( "/example/config.html", NULL, 0, NULL, 0, (void *)example_config ); if ( status != OK ) { log( lid, LOG, "_init: failed to add \"configuration\" callback to tree" ); (void) pthread_mutex_destroy( &mx ); (void) injun_remove_page( "/example/example.css" ); (void) injun_remove_page( "/example/index.html" ); (void) injun_remove_page( "/example/status.html" ); return( FAIL ); } /* well, we're all set so register with the injun administration gui */ status = injun_register_application( "Example", "/example/index.html", "Example application showing how to use " "injun's functions and features to make " "web enabled applications." ); /* this is not fatal, nor pretty ! */ if ( status != OK ) log( lid, LOG, "_init: failed to register with injun administration gui" ); /* and return */ return( OK ); } /*ARGSUSED*/ /******************************************************************************* * * Unit: example_dele() * * Description: removes the example application from injun * * Notes: we log whatever fails, theres no use in returning anything * but OK * * Parameters: argc/argv in standard format (NULL in this app) * * Globals: * * Returns: OK - always * ******************************************************************************/ int example_dele( int argc, char *argv[] ) { int status; /* remove the timeout first */ (void) injun_remove_timeout( (void *)example_timeout, (void *)timeout, NULL ); /* now do all the pages */ status = injun_remove_page( "/example/example.css" ); if ( status != OK ) log( lid, LOG, "_dele: failed to remove stylesheet %s from tree", "/example/example.css" ); status = injun_remove_page( "/example/index.html" ); if ( status != OK ) log( lid, LOG, "_dele: failed to remove %s from tree", "/example/index.html" ); status = injun_remove_page( "/example/status.html" ); if ( status != OK ) log( lid, LOG, "_dele: failed to remove %s from tree", "/example/status.html" ); /* remove the mutex */ status = pthread_mutex_destroy( &mx ); if ( status != OK ) log( lid, LOG, "_dele: failed to destroy the mutex" ); /* deregister with the injun administration gui */ status = injun_deregister_application( "Example" ); if ( status != OK ) log( lid, LOG, "_dele: failed to deregister" ); /* remove the logging for this module */ log_remove( lid ); /* and we're outta here */ return( OK ); } /******************************************************************************* * * Unit: example_make_page() * * Description: creates the finished web page appending a header and footer, * using this will give a standard, flexible look and feel ! * * Notes: allocates memory to *page which must be freed by caller * * Parameters: body - the web page to encapsulate * title - the title of the web page * style - the external stylesheet to reference from the page * page - the finished article * * Globals: none * * Returns: OK - the web page is contained in *page * FAIL - something went badly wrong * ******************************************************************************/ static int example_make_page( char *body, char *title, char *style, char **page ) { int status; char *head = NULL; /* temporary data */ /* initialise return parameter */ *page = NULL; /* now, add the header */ status = injun_add_header( body, title, B_TRUE, style, NULL, &head ); if ( status != OK ) { log( lid, LOG, "make_page: failed to add header onto web page" ); return( FAIL ); } /* and the footer */ status = injun_add_footer( head, page ); if ( status != OK ) { log( lid, LOG, "make_page: failed to add footer onto web page" ); free( head ); *page = NULL; return( FAIL ); } /* cleanup temporary data and return */ free( head ); return( OK ); } /*ARGSUSED*/ /******************************************************************************* * * Unit: example_status() * * Description: example callback serving a dynamic test web page * * Synopsis: first of all the dynamic information (request arguments in * this case) are sprintf'd into text strings. These are * then added into the page structure, an array or strings. * We then serve the header (HTTP). We then convert the array of * strings into one string which then gets a HTML header added * to it. After this any other arguments are converted to * strings and then written out. Finally we add a footer to * the end of the page and serve it. Easy, Eh ! * * Notes: this page can be used to test args passed to a callback * * Parameters: page - a pointer to the page object * args - the args that were contained in the request * * Globals: * * Returns: none * ******************************************************************************/ static void example_status( web_page_t *page, struct webcb_args_s *args ) { register int i; /* loop counter */ int length; char *header; char *body; char *footer; char buffer1[BUFSIZ]; /* character buffers */ char buffer2[BUFSIZ]; char buffer3[BUFSIZ]; char buffer4[BUFSIZ]; char buffer5[BUFSIZ]; char *page_html[] = { /* web page html */ "
\n", "

Example Dynamic Page

\n", "
\n", "\n", "\n", 0, 0, 0, 0, 0, 0 }; char *foot_html = /* web page footer */ "\n" "
\n", "This page is a dynamic web page which has been created on ", "the fly by an embedded routine. Below you can see the \n", "details of the request that the Injun web server ", "has passed onto this routine. \n", "
Static Web Page
\n"; /* do some clever things with the args */ (void) sprintf( buffer1, "%s%d\n", "File Descriptor", args->fd ); (void) sprintf( buffer2, "%s
%s
\n", "Full Request", args->buffer ); (void) sprintf( buffer3, "%s%s\n", "Processed Request", args->request ); (void) sprintf( buffer4, "%s%s\n", "Page Request", args->index ); (void) sprintf( buffer5, "%s%s (%s:%d)\n", "Requested by", args->hname, args->ip, args->port ); /* plumb the new entries into the page */ page_html[10] = buffer1; page_html[11] = buffer2; page_html[12] = buffer3; page_html[13] = buffer4; page_html[14] = buffer5; /* we don't know what the final length */ /* will be so we simply leave it at 0 */ injun_serve_header( args->fd, "text/html", 0 ); /* turn the array of character pointers into one string */ for( length = 0, i = 0; page_html[i] != NULL; i++ ) length += strlen(page_html[i]); body = (char *)calloc( length+1, 1 ); for( i = 0; page_html[i] != NULL; i++ ) (void) strcat( body, page_html[i] ); /* now add the header */ (void) injun_add_header( body, "Example Dynamic Page", B_FALSE, "example.css", NULL, &header ); free( body ); /* and write the page */ (void) write( args->fd, header, strlen(header) ); free( header ); /* now process the args (if any) */ if ( args->args->argc > 0 ) { for ( i = 0; i < args->args->argc; i++ ) { (void) sprintf( buffer1, "Arg %d%s = %s\n", i, args->args->argv[i].attr, args->args->argv[i].value ); (void) write( args->fd, buffer1, strlen(buffer1) ); } } else { (void) sprintf( buffer1, "No Args\n" ); (void) write( args->fd, buffer1, strlen(buffer1) ); } /* now serve the balance of the page */ (void) injun_add_footer( foot_html, &footer ); (void) write( args->fd, footer, strlen(footer) ); free( footer ); /* and we're outta here */ return; } /******************************************************************************* * * Unit: example_timeout() * * Description: reschedules another timeout and logs a message if necessary * * Notes: * * Parameters: args - timeout id * * Globals: number - number of this timeout * logtime - number of timeouts between logging something * * Returns: none * ******************************************************************************/ static void example_timeout( void *args ) { int status; int iv; /* check and set the timeout */ iv = interval - offset; if ( iv < 0 ) iv = MIN_TIMEOUT; if ( iv > MAX_TIMEOUT ) iv = MAX_TIMEOUT; /* re-add in the timeout straight away */ status = injun_add_timeout( iv, (void *)example_timeout, args ); if ( status != OK ) log( lid, LOG, "_timeout: failed to reschedule timeout" ); /* lock the mutex, number is shared data */ (void) pthread_mutex_lock( &mx ); /* log something every five hours */ if ( (number % logtime) == 0 ) log( lid, LOG, "_timeout: %s(%u), running every %d msecs", (char *)args, number, iv ); /* increment the timeout counter */ number++; /* unlock the mutex */ (void) pthread_mutex_unlock( &mx ); /* and we're done */ return; } /*ARGSUSED*/ /******************************************************************************* * * Unit: example_config() * * Description: callback routine called to configure this module * * Notes: this is ugly, dealing with text alway is ... * * Parameters: page - pointer to the web page * args - request arguments * * Returns: none * ******************************************************************************/ static void example_config( web_page_t *page, struct webcb_args_s *args ) { int i, value; char buffer1[BUFSIZ]; char buffer2[BUFSIZ]; char *page_html[] = { "\n", "\n\n", " \n", " Example Timeout Configuration\n", " \n", " \n\n", " \n\n", "\n", "
\n", "

Example Timeout Configuration

", "
\n\n", "
\n", " \n", 0 }; char *footer_html = { "
\n\n" "
\n\n" "

Continue

\n" "
\n" " \n\n" "\n" }; /* first off, check for arguments */ if ( args->args->argc == 0 ) { /* no arguments, serve the standard page */ serve_config_page( args->fd ); } else { /* arguments ! check and set each one ... */ for ( i = 0; i < args->args->argc; i++ ) { /* for each argument pair we must find out which */ /* has been set, verify it and carry the value */ /* through to our local variables. */ if ( strcmp(args->args->argv[i].attr,"maxt") == 0 ) { if ( args->args->argv[i].value != NULL ) { value = atoi( args->args->argv[i].value ); if ( value < MIN_TIMEOUT ) value = MIN_TIMEOUT; if ( value > MAX_TIMEOUT ) value = MAX_TIMEOUT; old_interval = interval; interval = value; } } if ( strcmp(args->args->argv[i].attr,"maxl") == 0 ) { if ( args->args->argv[i].value != NULL ) { value = atoi( args->args->argv[i].value ); if ( value < MIN_LOGTIME ) value = MIN_LOGTIME; if ( value > MAX_LOGTIME ) value = MAX_LOGTIME; old_logtime = logtime; logtime = value; } } if ( strcmp(args->args->argv[i].attr,"offs") == 0 ) { if ( args->args->argv[i].value != NULL ) { value = atoi(args->args->argv[i].value); if ( value < MIN_OFFSET ) value = MIN_OFFSET; if ( value > MAX_OFFSET ) value = MAX_OFFSET; old_offset = offset; offset = value; } } } /* find the length and serve the header */ injun_serve_header( args->fd, "text/html", 0 ); for( i = 0; page_html[i] != NULL; i++ ) (void) write( args->fd, page_html[i], strlen(page_html[i]) ); /* printout the new set of values */ (void) sprintf( buffer1, " \n" ); (void) strcat( buffer1, " Name\n" ); (void) strcat( buffer1, " Current\n" ); (void) strcat( buffer1, " Previous\n" ); (void) strcat( buffer1, " Description\n" ); (void) strcat( buffer1, " \n\n" ); (void) write( args->fd, buffer1, strlen(buffer1) ); (void) sprintf( buffer1, " \n" ); (void) strcat( buffer1, " Timeout\n" ); (void) sprintf( buffer2, " %d\n", interval ); (void) strcat( buffer1, buffer2 ); (void) sprintf( buffer2, " %d\n", old_interval ); (void) strcat( buffer1, buffer2 ); (void) strcat( buffer1, " Timeout interval in milliseconds\n" ); (void) strcat( buffer1, " \n\n" ); (void) write( args->fd, buffer1, strlen(buffer1) ); (void) sprintf( buffer1, " \n" ); (void) strcat( buffer1, " Logtime\n" ); (void) sprintf( buffer2, " %d\n", logtime ); (void) strcat( buffer1, buffer2 ); (void) sprintf( buffer2, " %d\n", old_logtime ); (void) strcat( buffer1, buffer2 ); (void) strcat( buffer1, " Number of timeouts between log messages\n" ); (void) strcat( buffer1, " \n\n" ); (void) write( args->fd, buffer1, strlen(buffer1) ); (void) sprintf( buffer1, " \n" ); (void) strcat( buffer1, " Offset\n" ); (void) sprintf( buffer2, " %d\n", offset ); (void) strcat( buffer1, buffer2 ); (void) sprintf( buffer2, " %d\n", old_offset ); (void) strcat( buffer1, buffer2 ); (void) strcat( buffer1, " Execution time of timeout in milliseconds\n" ); (void) strcat( buffer1, " \n\n" ); (void) write( args->fd, buffer1, strlen(buffer1) ); /* and the web page */ (void) write( args->fd, footer_html, strlen(footer_html) ); } /* and return */ return; } /******************************************************************************* * * Unit: serve_config_page() * * Description: serves a pretty static web page with some additional * dynamic information patched in. * * Notes: this is also ugly... * * Notes: none * * Parameters: fd - descriptor to write on * * Returns: none * ******************************************************************************/ static void serve_config_page( int fd ) { int i, length; char buffer1[SMLBUF]; char buffer2[SMLBUF]; char buffer3[SMLBUF]; char buffer4[SMLBUF]; char buffer5[SMLBUF]; char buffer6[SMLBUF]; char *load_html[] = { "\n", "\n\n", "\n", " Example Timeout Configuration \n", " \n", " \n", " \n\n", /* 9*/ "\n\n", "\n", "
\n", "

Example Timeout Configuration

\n", "
\n\n", "

This page allows you to change the tunable values of the example\n", " module. Fill in the values you wish to change and then select\n", " the submit button. Do not change these parameters unless you\n", " know what your doing !\n", "

\n\n", /*19*/ "
\n\n", "
\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n\n", /*29*/ " \n", " \n", " \n", /* 31, 32, 33 */ " \n", " \n", " \n\n", /*39*/ " \n", " \n", " \n", /* 41, 42, 43 */ " \n", " \n", " \n\n", /*49*/ " \n", " \n", " \n", /* 51, 52, 53 */ " \n", " \n", " \n\n", /*59*/ " \n", " \n", " \n\n", "
NameCurrentNewDescription
Timeout", 0, "Timeout interval in milliseconds
Logging interval", 0, "Number of interrupts between log messages
Timeout Offset", 0, "Number of milliseconds timeout takes to execute
\n", "
\n", "
\n", "
\n", "\n", "\n", 0 }; /* create the value strings */ (void) sprintf( buffer1, "%d", interval ); (void) sprintf( buffer2, "%d", logtime ); (void) sprintf( buffer3, "%d", offset ); (void) sprintf( buffer4, "%d", interval ); (void) sprintf( buffer5, "%d", logtime ); (void) sprintf( buffer6, "%d", offset ); /* and plumb them into the page */ load_html[32] = buffer1; load_html[35] = buffer4; load_html[42] = buffer2; load_html[45] = buffer5; load_html[52] = buffer3; load_html[55] = buffer6; /* find the length and serve the header */ for( i = 0, length = 0; load_html[i] != NULL; i++ ) length = length + strlen( load_html[i] ); injun_serve_header( fd, "text/html", length ); /* and the web page */ for( i = 0; load_html[i] != NULL; i++ ) (void) write( fd, load_html[i], strlen(load_html[i]) ); return; }