
/* This example keeps a log of HTTP requests over time, and
 * shows a graph of httpd usage per 5 second period
 *
 * Critical sections are used so that the datacollector
 * and the datareporter do not step on each other.
 *
 * Includes FTP server.
 * Includes SMTP server feature: change main title by mailing new subject
 * line as mail subject, to update@thismachine
 */
#include <rtos.h>
#include <net.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <graph.h>
#include <ftpd.h>
#include <httpd.h>
#include <smtpd.h>

#define GRWIDTH 200
#define GRHEIGHT 50

/*
 * Sample Data Collector
 *
 * This code is mostly in charge of aging the data history
 * every 5 seconds.
 *
 * It is placed in a separate thread so it is easy to read
 */

#define POINTS 20
int last_n_points[ POINTS ];    /* this is the series over time */
int curhits;                    /* this is the value in this period */
crit_x *collector_cs;
void collector( DWORD param )
{
    int i;

    /* clear history */
    memset( last_n_points, 0, sizeof( last_n_points ));

    /* clear counter */
    curhits = 0;

    /* we will use a critical section so that collector and
     * reporter are not interrupting each other
     */
    collector_cs = cs_alloc();

    do {
        rt_sleep( 5000 );    /* collect data for 5 seconds */

        /* react to that collected data
         * start by locking it
         */
        cs_enter( collector_cs );

        /* remove the last one from history */
        for ( i = 0 ; i < POINTS - 2 ; ++i )
            last_n_points[ i ] = last_n_points[ i + 1 ];
        /* and include the most recent */
        last_n_points[ POINTS - 2 ] = curhits;

        /* and reset the input to 0 for next round */
        curhits = 0;
        cs_exit( collector_cs );
    } while ( 1 );
}

char newmsg[ 80 ] = "";

void web_help( tcp_Socket *s )
{
    sock_puts( s, "\r\n<html><head><title>");
    sock_puts( s, (*newmsg) ? newmsg : "Welcome" );  /* change with SMTP */
    sock_puts( s, "</title></head>");
    sock_puts(s, "<a href=\"time\">Show Time</a><br>");
    sock_puts(s, "<a href=\"mem\">Show Free Memory</a><br>");
    sock_puts(s, "<p>The graph below is a real time graph of "
                 "server usage in 5 second increments.</p>");
    sock_puts(s, "<img src=\"graph.gif\" WIDTH=400 HEIGHT=100 >");
    html_tail( s );
}

void web_time( tcp_Socket *s )
{
    time_t t;
    time( &t );
    html_hdr( s, "current time");
    sock_puts( s,"The current time is ");
    sock_puts( s, ctime( &t ));
    html_tail( s );
}
void web_mem( tcp_Socket *s )
{
    char buffer[ 128 ];

    html_hdr( s, "free memory");
    sprintf( buffer, "There are %lu free bytes.",
        kcorefree());
    sock_puts( s, buffer );
    html_tail( s );
}

/* graph code */
crit_x *graph_cs = NULL;
void web_graph( tcp_Socket *s )
{
    graph_x *g;

    kblock();
    if ( graph_cs == NULL )
        graph_cs = cs_alloc();
    kunblock();

    sock_puts( s, "");

    cs_enter( graph_cs );

    g = gr_alloc( GRWIDTH, GRHEIGHT);
    if ( g != NULL ) {
        gr_background( g, 7 );

        /* put a title on the graph */
        gr_text_at( g , "Web Hits", GRWIDTH/2 - 15, GRHEIGHT - 10, 0 );

        /* we need to lock the data for this time */
        cs_enter( collector_cs );

        last_n_points[ POINTS - 1 ] = curhits;

        gr_linegraph( g, POINTS, last_n_points, NULL, "now", 0, 1 );

        /* we don't need the lock on the data anymore */
        cs_exit( collector_cs );

        sock_mode( s, TCP_MODE_BINARY );
        gr_gif( s, g );     /* write the graph out as a GIF file */
        gr_free( g );
    }
    cs_exit( graph_cs );
}

/*
 * - the web server calls this proc for each web request
 * - it is called in the context of *one* of the HTTPD threads,
 *   though which is not known or important
 * - multiple threads may be in the same proc at the same time
 */
void user_proc( tcp_Socket *s, char *cmd, char *file, char *ext )
{
    /* increment the data points */
    curhits++;

    /* prepare output */
    if ( !stricmp( ext, "gif"))  {
        if ( !stricmp( file, "/graph"))
            web_graph( s );
    } else {
        /* non gif stuff */
        if ( !stricmp( file, "/" )) web_help( s );
        else if ( !stricmp( file, "/time" )) web_time( s );
        else if ( !stricmp( file, "/mem" )) web_mem( s );
        else web_help( s );
    }
}

void mailproc( char *from, char *to, char *subject )
{
    char *p;
    if ( ( p = strchr( to, '@')) != NULL ) *p = 0;
    if ( !stricmp( to, "update") && *subject )
        strcpy( newmsg, subject );
}

main()
{
    int i;
    kdebug = 1;
    rt_init(100);
    kpreemptive = 1;        /* enable pre-emptive multithreading */
    sock_init();            /* initialize network */

    cputs("starting...\r\n");

    rt_newthread( collector, 1,2048, 0, "collector" );
    rt_newthread( ftpdthread, 1,2048, 0, "ftpd" );
    rt_newthread( smtpdthread, (DWORD)&mailproc, 2048, 0, "smtpd");

#define MAXHTTPD 5
    for ( i = 0 ; i < MAXHTTPD; ++i )
        rt_newthread( httpdthread, (DWORD)&user_proc, 4096, 0, "httpd worker" );
    do {
        /* nothing */
        rt_sleep( 1000 );
    } while ( 1 );
}

