# HG changeset patch # User nickg # Date 1040555340 0 # Node ID ca4f29d41b1894cacf88567ccbbcc7f2d81af302 # Parent a358ddc533a15ea20ccd273e261741b79ee78c1a Created new HTTPD package. diff --git a/packages/net/httpd/current/ChangeLog b/packages/net/httpd/current/ChangeLog new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/ChangeLog @@ -0,0 +1,16 @@ +2002-12-06 Nick Garnett + + * include/httpd.h: + * src/init.cxx: + * src/httpd.c: + * src/monitor.c: + * doc/httpd.sgml: + * cdl/httpd.cdl: + Created HTTPD package. + +# Copyright (C) 2002 Nick Garnett +# All Rights Reserved. +# +# Permission is granted to use, copy, modify and redistribute this +# file. + \ No newline at end of file diff --git a/packages/net/httpd/current/cdl/httpd.cdl b/packages/net/httpd/current/cdl/httpd.cdl new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/cdl/httpd.cdl @@ -0,0 +1,183 @@ +# ==================================================================== +# +# httpd.cdl +# +# HTTPD configuration data +# +# ==================================================================== +#####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2002 Nick Garnett +## +## eCos is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free +## Software Foundation; either version 2 or (at your option) any later version. +## +## eCos is distributed in the hope that it will be useful, but WITHOUT ANY +## WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## +## You should have received a copy of the GNU General Public License along +## with eCos; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +## +## As a special exception, if other files instantiate templates or use macros +## or inline functions from this file, or you compile this file and link it +## with other works to produce a work based on this file, this file does not +## by itself cause the resulting work to be covered by the GNU General Public +## License. However the source code for this file must still be made available +## in accordance with section (3) of the GNU General Public License. +## +## This exception does not invalidate any other reasons why a work based on +## this file might be covered by the GNU General Public License. +## +## ------------------------------------------- +#####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): nickg +# Original data: nickg +# Contributors: +# Date: 2002-10-15 +# +#####DESCRIPTIONEND#### +# +# ==================================================================== + +cdl_package CYGPKG_HTTPD { + display "HTTP Daemon" + parent CYGPKG_NET +# doc doc/index.html + include_dir cyg/httpd + requires CYGPKG_IO + requires { 0 != CYGINT_ISO_STDLIB_STRCONV } + requires { 0 != CYGINT_ISO_STDIO_FORMATTED_IO } + requires { 0 != CYGINT_ISO_STRING_STRFUNCS } + requires { 0 != CYGINT_ISO_ERRNO } + requires { 0 != CYGINT_ISO_ERRNO_CODES } + requires CYGPKG_NET + description " + HTTP Daemon. This is an embedded HTTP server for use with + applications in eCos.This server is specifically aimed at + the remote control and monitoring requirements of embedded + applications. For this reason the emphasis is on dynamically + generated content, simple forms handling and a basic CGI + interface. It is NOT intended to be a general purpose server for + delivering arbitrary web content." + + compile httpd.c + compile -library=libextras.a init.cxx monitor.c + + cdl_option CYGNUM_HTTPD_SERVER_PORT { + display "HTTP port" + flavor data + default_value 80 + description "HTTP port to which browsers will connect. + This defaults to the standard port 80, but may + be changed to any other port number if required." + } + + cdl_option CYGDAT_HTTPD_SERVER_ID { + display "HTTP server ID" + flavor data + default_value { "\"eCos/1.0\"" } + description "This is the string that will be used as the server + identifier in the HTTP header." + } + + cdl_option CYGNUM_HTTPD_THREAD_COUNT { + display "HTTPD thread count" + flavor data + default_value 1 + description "The HTTP server can be configured to use more than + one thread to service requests. This is useful if you + expect to serve complex pages, or if you expect to have + several simultaneous users. For most purposes, just + one thread is perfectly adequate." + } + + cdl_option CYGNUM_HTTPD_THREAD_PRIORITY { + display "HTTPD thread priority" + flavor data + default_value { CYGNUM_KERNEL_SCHED_PRIORITIES/2 } + legal_values 0 to CYGNUM_KERNEL_SCHED_PRIORITIES + description "The HTTP server threads can be run at any priority. + The exact priority depends on the importance of the + server relative to the rest of the system. The default + is to put it in the middle of the priority range to provide + reasonable response without impacting genuine high + priority threads." + } + + cdl_option CYGNUM_HTTPD_THREAD_STACK_SIZE { + display "HTTPD thread stack size" + flavor data + default_value 2048 + description "This is the amount of stack to be allocated for each + of the HTTPD threads. This quantity is in addition to the values + of CYGNUM_HAL_STACK_SIZE_MINIMUM and + CYGNUM_HTTPD_SERVER_BUFFER_SIZE." + } + + cdl_option CYGNUM_HTTPD_SERVER_BUFFER_SIZE { + display "HTTPD server buffer size" + flavor data + default_value 256 + description "This defines the size of the buffer used to receive the first + line of each HTTP request. If you expect to use particularly + long URLs or have very complex forms, this should be increased." + } + + cdl_option CYGNUM_HTTPD_SERVER_DELAY { + display "HTTPD server startup delay" + flavor data + default_value 0 + description "This defines the number of system clock ticks that the HTTP + server will wait before initializing itself and spawning any + extra server threads. This is to give the application a chance + to initialize properly without any interference from the HTTPD." + } + + cdl_component CYGPKG_HTTPD_MONITOR { + display "Simple Web System Monitor" + default_value 1 + description "This enables a simple system monitor that displays the + status of an eCos system using a small number of HTML pages." + + compile -library=libextras.a monitor.c + } + + cdl_component CYGPKG_HTTPD_OPTIONS { + display "HTTP server build options" + flavor none + no_define + + cdl_option CYGPKG_HTTPD_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "-D__ECOS" } + description " + This option modifies the set of compiler flags for + building the HTTP server package. + These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_HTTPD_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building the HTTP server package. These flags are removed from + the set of global flags if present." + } + } +} + +# EOF httpd.cdl diff --git a/packages/net/httpd/current/doc/httpd.sgml b/packages/net/httpd/current/doc/httpd.sgml new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/doc/httpd.sgml @@ -0,0 +1,532 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Embedded HTTP Server + +Embedded HTTP Server + + +Intrduction + +The eCos HTTPD package provides a simple HTTP +server for use with applications in eCos. This server is specifically +aimed at the remote control and monitoring requirements of embedded +applications. For this reason the emphasis is on dynamically generated +content, simple forms handling and a basic CGI interface. It is +not intended to be a general purpose server for +delivering arbitrary web content. For these purposes a port of the +GoAhead web server is available from www.goahead.com. + + + + +Server Organization + +The server consists of one or more threads running in parallel to any +application threads and which serve web pages to clients. Apart from +defining content, the application does not need to do anything to +start the HTTP server. + + +The HTTP server is started by a static constructor. This simply +creates an initial thread and sets it running. Since this is called +before the scheduler is started, nothing will happen until the +application calls cyg_scheduler_start(). + + +When the thread gets to run it first optionally delays for some period +of time. This is to allow the application to perform any +initialization free of any interference from the HTTP server. When the +thread does finally run it creates a socket, binds it to the HTTP +server port, and puts it into listen mode. It will then create any +additional HTTPD server threads that have been configured before +becoming a server thread itself. + + +Each HTTPD server thread simply waits for a connection to be made to +the server port. When the connection is made it reads the HTTP request +and extracts the filename being accessed. If the request also contains +form data, this is also preserved. The filename is then looked up in a +table. + + +Each table entry contains a filename pattern string, a +pointer to a handler function, and a user defined argument for the +function. Table entries are defined using the same link-time table +building mechanism used to generate device tables. This is all handled +by the CYG_HTTPD_TABLE_ENTRY() macro which has the +following format: + + + +#include <cyg/httpd/httpd.h> + +CYG_HTTPD_TABLE_ENTRY( __name, __pattern, __handler, __arg ) + + + +The __name argument is a variable name for the +table entry since C does not allow us to define anonymous data +structures. This name should be chosen so that it is unique and does +not pollute the name space. The __pattern +argument is the match pattern. The __handler +argument is a pointer to the handler function and +__arg the user defined value. + + +The link-time table building means that several different pieces of +code can define server table entries, and so long as the patterns do +not clash they can be totally oblivious of each other. However, note +also that this mechanism does not guarantee the order in which entries +appear, this depends on the order of object files in the link, which +could vary from one build to the next. So any tricky pattern matching +that relies on this may not always work. + + +A request filename matches an entry in the table if either it exactly +matches the pattern string, or if the pattern ends in an asterisk, and +it matches everything up to that point. So for example the pattern +"/monitor/threads.html" will only match that exact filename, +but the pattern "/monitor/thread-*" will match +"/monitor/thread-0040.html", +"/monitor/thread-0100.html" and any other filename starting +with "/monitor/thread-". + + +When a pattern is matched, the hander function is called. It has the +following prototype: + + +cyg_bool cyg_httpd_handler(FILE *client, + char *filename, + char *formdata, + void *arg); + + +The client argument is the TCP connection to +the client: anything output through this stream will be returned to +the browser. The filename argument is the +filename from the HTTP request and the formdata +argument is any form response data, or NULL if none was sent. The +arg argument is the user defined value from the +table entry. + + +The handler is entirely responsible for generating the response to the +client, both HTTP header and content. If the handler decides that it +does not want to generate a response it can return +false, in which case the table scan is resumed for +another match. If no match is found, or no handler returns true, then +a default response page is generated indicating that the requested +page cannot be found. + + +Finally, the server thread closes the connection to the client and +loops back to accept a new connection. + + + + + + +Server Configuration + +The HTTP server has a number of configuration options: + + + +<literal>CYGNUM_HTTPD_SERVER_PORT</literal> + +This option defines the TCP port that the server will listen on. It +defaults to the standard HTTP port number 80. It may be changed to a +different number if, for example, another HTTP server is using the +main HTTP port. + + + + +<literal>CYGDAT_HTTPD_SERVER_ID</literal> + +This is the string that is reported to the client in the +"Server:" field of the HTTP header. + + + + +<literal>CYGNUM_HTTPD_THREAD_COUNT</literal> + +The HTTP server can be configured to use more than one thread to +service HTTP requests. If you expect to serve complex pages with many +images or other components that are fetched separately, or if any +pages may take a long time to send, then it may be useful to increase +the number of server threads. For most uses, however, the connection +queuing in the TCP/IP stack and the speed with which each page is +generated, means that a single thread is usually adequate. + + + + +<literal>CYGNUM_HTTPD_THREAD_PRIORITY</literal> + +The HTTP server threads can be run at any priority. The exact priority +depends on the importance of the server relative to the rest of the +system. The default is to put them in the middle of the priority range +to provide reasonable response without impacting genuine high priority +threads. + + + + +<literal>CYGNUM_HTTPD_THREAD_STACK_SIZE</literal> + +This is the amount of stack to be allocated for each of the HTTPD +threads. The actual stack size allocated will be this value plus the +values of CYGNUM_HAL_STACK_SIZE_MINIMUM and +CYGNUM_HTTPD_SERVER_BUFFER_SIZE. + + + + +<literal>CYGNUM_HTTPD_SERVER_BUFFER_SIZE</literal> + +This defines the size of the buffer used to receive the first line of +each HTTP request. If you expect to use particularly long URLs or have +very complex forms, this should be increased. + + + + +<literal>CYGNUM_HTTPD_SERVER_DELAY</literal> + +This defines the number of system clock ticks that the HTTP server +will wait before initializing itself and spawning any extra server +threads. This is to give the application a chance to initialize +properly without any interference from the HTTPD. + + + + + + + + +Support Functions and Macros + +The emphasis of this server is on dynamically generated content, +rather than fetching it from a filesystem. To do this the handler +functions make calls to fprintf() and +fputs(). Such handler functions would end up a +mass of print calls, with the actual structure of the HTML page hidden +in the format strings and arguments, making maintenance and debugging +very difficult. Such an approach would also result in the definition +of many, often only slightly different, format strings, leading to +unnecessary bloat. + + +In an effort to expose the structure of the HTML in the structure of +the C code, and to maximize the sharing of string constants, the +cyg/httpd/httpd.h header file defines a set of +helper functions and macros. Most of these are wrappers for predefined +print calls on the client stream passed to the +hander function. For examples of their use, see the System Monitor +example. + + + +All arguments to macros are pointers to strings, unless otherwise +stated. In general, wherever a function or macro has an +attr or __attr +parameter, then the contents of this string will be inserted into the +tag being defined as HTML attributes. If it is a NULL or empty string +it will be ignored. + + + + +HTTP Support + +void cyg_http_start( FILE *client, char *content_type, int content_length ); +void cyg_http_finish( FILE *client ); +#define html_begin(__client) +#define html_end( __client ) + + +The function cyg_http_start() generates a simple +HTTP response header containing the value of +CYGDAT_HTTPD_SERVER_ID in the "Server" field, and the +values of content_type and +content_length in the "Content-type" +and "Content-length" field respectively. The function +cyg_http_finish() just adds an extra newline to +the end of the output and then flushes it to force the data out to the +client. + + +The macro html_begin() generates an HTTP header +with a "text/html" content type followed by an opening +"<html>" tag. html_end() generates +a closing "</html>" tag and calls +cyg_http_finish(). + + + + +General HTML Support + +void cyg_html_tag_begin( FILE *client, char *tag, char *attr ); +void cyg_html_tag_end( FILE *client, char *tag ); +#define html_tag_begin( __client, __tag, __attr ) +#define html_tag_end( __client, __tag ) +#define html_head( __client, __title, __meta ) +#define html_body_begin( __client, __attr ) +#define html_body_end( __client ) +#define html_heading( __client, __level, __heading ) +#define html_para_begin( __client, __attr ) +#define html_url( __client, __text, __link ) +#define html_image( __client, __source, __alt, __attr ) + + +The function cyg_html_tag_begin() generates an +opening tag with the given name. The function +cyg_html_tag_end() generates a closing tag with +the given name. The macros html_tag_begin() and +html_tag_end are just wrappers for these functions. + + +The macro html_head() generates an HTML header +section with __title as the title. The +__meta argument defines any meta tags that will +be inserted into the header. html_body_begin() and +html_body_end generate HTML body begin and end +tags. + + +html_heading() generates a complete HTML header +where __level is a numerical level, between 1 +and 6, and __heading is the heading +text. html_para_begin() generates a paragraph +break. + + +html_url() inserts a URL where +__text is the displayed text and +__link is the URL of the linked +page. html_image() inserts an image tag where +__source is the URL of the image to be +included and __alt is the alternative text for +when the image is not displayed. + + + + +Table Support + +#define html_table_begin( __client, __attr ) +#define html_table_end( __client ) +#define html_table_header( __client, __content, __attr ) +#define html_table_row_begin( __client, __attr ) +#define html_table_row_end( __client ) +#define html_table_data_begin( __client, __attr ) +#define html_table_data_end( __client ) + + +html_table_begin() starts a table and +html_table_end() end +it. html_table_header() generates a simple table +column header containg the string __content. + + +html_table_row_begin() and +html_table_row_end() begin and end a table row, +and similarly html_table_data_begin() and +html_table_data_end() begin and end a table +entry. + + + + +Forms Support + +#define html_form_begin( __client, __url, __attr ) +#define html_form_end( __client ) +#define html_form_input( __client, __type, __name, __value, __attr ) +#define html_form_input_radio( __client, __name, __value, __checked ) +#define html_form_input_checkbox( __client, __name, __value, __checked ) +#define html_form_input_hidden( __client, __name, __value ) +#define html_form_select_begin( __client, __name, __attr ) +#define html_form_option( __client, __value, __label, __selected ) +#define html_form_select_end( __client ) +void cyg_formdata_parse( char *data, char *list[], int size ); +char *cyg_formlist_find( char *list[], char *name ); + + +html_form_begin() begins a form, the +__url argument is the value for the +action +attribute. html_form_end() ends the form. + + +html_form_input() defines a general form input +element with the given type, name and +value. html_form_input_radio creates a radio button +with the given name and value; the __checked +argument is a boolean expression that is used to determine whether the +checked attribute is added to the tag. Similarly +html_form_input_checkbox() defines a checkbox +element. html_form_input_hidden() defines a hidden +form element with the given name and value. + + +html_form_select_begin() begins a multiple choice +menu with the given name. html_form_select_end() +end it. html_form_option() defines a menu entry +with the given value and label; the __selected +argument is a boolean expression controlling whether the +selected attribute is added to the tag. + + +cyg_formdata_parse() converts a form response +string into an NULL-terminated array of +"name=value" entries. The data +argument is the string as passed to the handler function; note that +this string is not copied and will be updated in place to form the +list entries. list is a pointer to an array of +character pointers, and is size elements long. +cyg_formlist_find() searches a list generated by +cyg_formdata_parse() and returns a pointer to the +value part of the string whose name part matches +name; if there is no match it will return +NULL. + + + + +Predefined Handlers + + +int cyg_httpd_send_html( FILE *client, char *filename, char *request, void *arg ); + +typedef struct +{ + char *content_type; + cyg_uint32 content_length; + cyg_uint8 *data; +} cyg_httpd_data; +#define CYG_HTTPD_DATA( __name, __type, __length, __data ) + +int cyg_httpd_send_data( FILE *client, char *filename, char *request, void *arg ); + + + +The HTTP server defines a couple of predefined handers to make it +easier to deliver simple, static content. + + +cyg_httpd_send_html() takes a +NULL-terminated string as the argument and sends it +to the client with an HTTP header indicating that it is HTML. The +following is an example of its use: + + + +char cyg_html_message[] = "<head><title>Welcome</title></head>\n" + "<body><h2>Welcome to my Web Page</h2></body>\n" + +CYG_HTTPD_TABLE_ENTRY( cyg_html_message_entry, + "/message.html", + cyg_httpd_send_html, + cyg_html_message ); + + + +cyg_httpd_send_data() Sends arbitrary data to the +client. The argument is a pointer to a cyg_httpd_data +structure that defines the content type and length of the data, and a +pointer to the data itself. The CYG_HTTPD_DATA() +macro automates the definition of the structure. Here is a typical +example of its use: + + + +static cyg_uint8 ecos_logo_gif[] = { + ... +}; + +CYG_HTTPD_DATA( cyg_monitor_ecos_logo_data, + "image/gif", + sizeof(ecos_logo_gif), + ecos_logo_gif ); + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_ecos_logo, + "/monitor/ecos.gif", + cyg_httpd_send_data, + &cyg_monitor_ecos_logo_data ); + + + + + + + + + +System Monitor + +Included in the HTTPD package is a simple System Monitor that is +intended to act as a test and an example of how to produce servers. +It is also hoped that it might be of some use in and of itself. + + +The System Monitor is intended to work in the background of any +application. Adding the network stack and the HTTPD package to any +configuration will enable the monitor by default. It may be disabled +by disabling the CYGPKG_HTTPD_MONITOR option. + + +The monitor is intended to be simple and self-explanatory in use. It +consists of four main pages. The thread monitor page presents a table +of all current threads showing such things as id, state, priority, +name and stack dimensions. Clicking on the thread ID will link to a +thread edit page where the thread's state and priority may be +manipulated. The interrupt monitor just shows a table of the current +interrupts and indicates which are active. The memory monitor shows a +256 byte page of memory, with controls to change the base address and +display element size. The network monitor page shows +information extracted from the active network interfaces and +protocols. Finally, if kernel instrumentation is enabled, the +instrumentation page provides some controls over the instrumentation +mechanism, and displays the instrumentation buffer. + + + + + + + diff --git a/packages/net/httpd/current/include/httpd.h b/packages/net/httpd/current/include/httpd.h new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/include/httpd.h @@ -0,0 +1,279 @@ +#ifndef CYGONCE_NET_HTTPD_HTTPD_H +#define CYGONCE_NET_HTTPD_HTTPD_H +/* ================================================================= + * + * httpd.h + * + * A simple embedded HTTP server + * + * ================================================================= + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating + * System. + * Copyright (C) 2002 Nick Garnett + * + * eCos is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 or (at your option) + * any later version. + * + * eCos is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with eCos; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or + * use macros or inline functions from this file, or you compile this + * file and link it with other works to produce a work based on this + * file, this file does not by itself cause the resulting work to be + * covered by the GNU General Public License. However the source code + * for this file must still be made available in accordance with + * section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work + * based on this file might be covered by the GNU General Public + * License. + * + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + * ================================================================= + * #####DESCRIPTIONBEGIN#### + * + * Author(s): nickg@calivar.com + * Contributors: nickg@calivar.com + * Date: 2002-10-14 + * Purpose: + * Description: + * + * ####DESCRIPTIONEND#### + * + * ================================================================= + */ + +#include +#include +#include + +#include + +#include + +/* ================================================================= */ +/* Lookup Table + * + * + */ + +typedef cyg_bool cyg_httpd_handler(FILE *client, char *filename, + char *formdata, void *arg); + +struct cyg_httpd_table_entry +{ + char *pattern; + cyg_httpd_handler *handler; + void *arg; +} CYG_HAL_TABLE_TYPE; + +typedef struct cyg_httpd_table_entry cyg_httpd_table_entry; + +#define CYG_HTTPD_TABLE_ENTRY( __name, __pattern, __handler, __arg ) \ +cyg_httpd_table_entry __name CYG_HAL_TABLE_ENTRY( httpd_table ) = { __pattern, __handler, __arg } + +/* ================================================================= */ +/* Useful handler functions + */ + +/* ----------------------------------------------------------------- */ +/* + */ + +__externC int cyg_httpd_send_html( FILE *client, char *filename, + char *request, void *arg ); + +/* ----------------------------------------------------------------- */ +/* + */ + +typedef struct +{ + char *content_type; + cyg_uint32 content_length; + cyg_uint8 *data; +} cyg_httpd_data; + +__externC int cyg_httpd_send_data( FILE *client, char *filename, + char *request, void *arg ); + +#define CYG_HTTPD_DATA( __name, __type, __length, __data ) \ +cyg_httpd_data __name = { __type, __length, __data } + +/* ================================================================= */ +/* HTTP and HTML helper macros and functions + */ + +/* ----------------------------------------------------------------- */ +/* HTTP header support + * + * cyg_http_start() sends an HTTP header with the given content type + * and length. cyg_http_finish() terminates an HTTP send. + * html_begin() starts an HTML document, and html_end() finishes it. + */ + +__externC void cyg_http_start( FILE *client, char *content_type, + int content_length ); +__externC void cyg_http_finish( FILE *client ); + +#define html_begin(__client) \ + cyg_http_start( __client, "text/html", 0 ); \ + html_tag_begin( __client, "html", "" ) + +#define html_end( __client ) \ + html_tag_end( __client, "html" ); \ + cyg_http_finish( client ) + +/* ----------------------------------------------------------------- */ +/* + */ + + +__externC void cyg_html_tag_begin( FILE *client, char *tag, char *attr ); +__externC void cyg_html_tag_end( FILE *client, char *tag ); + +#define html_tag_begin( __client, __tag, __attr ) \ + cyg_html_tag_begin( __client, __tag, __attr ) + +#define html_tag_end( __client, __tag ) cyg_html_tag_end( __client, __tag ) + + +/* ----------------------------------------------------------------- */ +/* + */ + + +#define html_head( __client, __title, __meta ) \ +{ \ + fprintf(__client, "<%s><%s>", "head", "title" ); \ + fputs( __title, __client ); \ + fprintf(__client, "%s\n", "title", __meta, "head"); \ +} + +#define html_body_begin( __client, __attr ) \ + cyg_html_tag_begin( __client, "body", __attr ); + +#define html_body_end( __client ) \ + cyg_html_tag_end( __client, "body" ); + +#define html_heading( __client, __level, __heading ) \ + fprintf(__client,"%s\n",__level,__heading,__level); + +/* ----------------------------------------------------------------- */ +/* + */ + + +#define html_url( __client, __text, __link ) \ + fprintf( __client, "%s\n",__link,__text); + +#define html_para_begin( __client, __attr ) \ + cyg_html_tag_begin( __client, "p", __attr ); + +#define html_image( __client, __source, __alt, __attr ) \ + fprintf( __client, "<%s %s=\"%s\" %s=\"%s\" %s>\n", "img", \ + "src",__source, \ + "alt",__alt, \ + (__attr)?(__attr):"" ); + +/* ----------------------------------------------------------------- */ +/* + */ + + +#define html_table_begin( __client, __attr ) \ + cyg_html_tag_begin( __client, "table", __attr ); + +#define html_table_end( __client ) \ + cyg_html_tag_end( __client, "table" ); + +#define html_table_header( __client, __content, __attr ) \ +{ \ + cyg_html_tag_begin( __client, "th", __attr); \ + fputs( __content, __client ); \ + cyg_html_tag_end( __client, "th" ); \ +} + +#define html_table_row_begin( __client, __attr ) \ + cyg_html_tag_begin( __client, "tr", __attr ); + +#define html_table_row_end( __client ) \ + cyg_html_tag_end( __client, "tr" ); + +#define html_table_data_begin( __client, __attr ) \ + cyg_html_tag_begin( __client, "td", __attr ); + +#define html_table_data_end( __client ) \ + cyg_html_tag_end( __client, "td" ); + +/* ----------------------------------------------------------------- */ +/* + */ + + +#define html_form_begin( __client, __url, __attr ) \ + fprintf(__client, "<%s %s=\"%s\" %s>\n","form", \ + "action",__url, \ + (__attr)?(__attr):"" ); + +#define html_form_end( __client ) \ + cyg_html_tag_end( __client, "form" ); + +#define html_form_input( __client, __type, __name, __value, __attr ) \ +{ \ + char *__lattr = (__attr); \ + fprintf(__client, "<%s %s=\"%s\" %s=\"%s\" %s=\"%s\" %s>\n","input", \ + "type",__type, \ + "name",__name, \ + "value",__value, \ + __lattr?__lattr:"" ); \ +} + +#define html_form_input_radio( __client, __name, __value, __checked ) \ + html_form_input( __client, "radio", __name, __value, (__checked)?"checked":"" ) + +#define html_form_input_checkbox( __client, __name, __value, __checked ) \ + html_form_input( __client, "checkbox", __name, __value, (__checked)?"checked":"" ) + +#define html_form_input_hidden( __client, __name, __value ) \ + html_form_input( __client, "hidden", __name, __value, "" ) + +#define html_form_select_begin( __client, __name, __attr ) \ + fprintf( __client, "<%s %s=\"%s\" %s>\n","select", \ + "name",__name, \ + (__attr)?(__attr):"" ); + +#define html_form_option( __client, __value, __label, __selected ) \ + fprintf( __client, "<%s %s=\"%s\" %s>\n","option", \ + "value", __value, \ + (__selected)?"selected":"" ); \ + fputs(__label, __client ); + +#define html_form_select_end( __client ) \ + cyg_html_tag_end( __client, "select" ); + + +/* ================================================================= */ +/* + */ + + +__externC void cyg_formdata_parse( char *data, char *list[], int size ); + +__externC char *cyg_formlist_find( char *list[], char *name ); + +/* ----------------------------------------------------------------- */ +#endif /* CYGONCE_NET_HTTPD_HTTPD_H */ +/* end of httpd.c */ diff --git a/packages/net/httpd/current/src/httpd.c b/packages/net/httpd/current/src/httpd.c new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/src/httpd.c @@ -0,0 +1,520 @@ +/* ================================================================= + * + * httpd.c + * + * A simple embedded HTTP server + * + * ================================================================= + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating + * System. + * Copyright (C) 2002 Nick Garnett. + * + * eCos is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 or (at your option) + * any later version. + * + * eCos is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with eCos; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or + * use macros or inline functions from this file, or you compile this + * file and link it with other works to produce a work based on this + * file, this file does not by itself cause the resulting work to be + * covered by the GNU General Public License. However the source code + * for this file must still be made available in accordance with + * section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work + * based on this file might be covered by the GNU General Public + * License. + * + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + * ================================================================= + * #####DESCRIPTIONBEGIN#### + * + * Author(s): nickg@calivar.com + * Contributors: nickg@calivar.com + * Date: 2002-10-14 + * Purpose: + * Description: + * + * ####DESCRIPTIONEND#### + * + * ================================================================= + */ + +#include +#include +#include + +#include /* tracing macros */ +#include /* assertion macros */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* ================================================================= */ + +#if 0 +#define HTTPD_DIAG diag_printf +#else +#define HTTPD_DIAG(...) +#endif + +/* ================================================================= */ +/* Server socket address and file descriptor. + */ + +static struct sockaddr_in server_address; + +static int server_socket = -1; + +/* ================================================================= */ +/* Thread stacks, etc. + */ + +static cyg_uint8 httpd_stacks[CYGNUM_HTTPD_THREAD_COUNT] + [CYGNUM_HAL_STACK_SIZE_MINIMUM+ + CYGNUM_HTTPD_SERVER_BUFFER_SIZE+ + CYGNUM_HTTPD_THREAD_STACK_SIZE]; + +static cyg_handle_t httpd_thread[CYGNUM_HTTPD_THREAD_COUNT]; + +static cyg_thread httpd_thread_object[CYGNUM_HTTPD_THREAD_COUNT]; + +/* ================================================================= */ +/* Filename lookup table + */ + +CYG_HAL_TABLE_BEGIN( cyg_httpd_table, httpd_table ); +CYG_HAL_TABLE_END( cyg_httpd_table_end, httpd_table ); + +__externC cyg_httpd_table_entry cyg_httpd_table[]; +__externC cyg_httpd_table_entry cyg_httpd_table_end[]; + +/* ================================================================= */ +/* Page not found message + */ + +static char cyg_httpd_not_found[] = +"Page Not found\n" +"

The requested URL was not found on this server.

\n"; + +/* ================================================================= */ +/* Simple pattern matcher for filenames + * + * This performs a simple pattern match between the given name and the + * pattern. At present the only matching supported is either exact, or + * if the pattern ends in * then that matches all remaining + * characters. At some point we might want to implement a more + * complete regular expression parser here. + */ + +static cyg_bool match( char *name, char *pattern ) +{ + while( *name != 0 && *pattern != 0 && *name == *pattern ) + name++, pattern++; + + if( *name == 0 && *pattern == 0 ) + return true; + + if( *pattern == '*' ) + return true; + + return false; +} + +/* ================================================================= */ +/* Main HTTP server + * + * This just loops, collects client connections, reads the HTTP + * header, look it up in the table and calls the handler. + */ + +static void cyg_httpd_server( cyg_addrword_t arg ) +{ + do + { + int err; + int client_socket; + struct sockaddr_in client_address; + int calen; + int nlc = 0; + char request[CYGNUM_HTTPD_SERVER_BUFFER_SIZE]; + FILE *client; + cyg_httpd_table_entry *entry = cyg_httpd_table; + char *filename; + char *formdata = NULL; + char *p; + cyg_bool success = false; + + /* Wait for a connection. + */ + client_socket = accept( server_socket, (struct sockaddr *)&client_address, &calen ); + + HTTPD_DIAG("Connection from %08x[%d]\n",client_address.sin_addr.s_addr, + client_address.sin_port); + + /* Convert the file descriptor to a C library FILE object so + * we can use fprintf() and friends on it. + */ + client = fdopen( client_socket, "r+"); + + /* We are really only interested in the first line. + */ + fgets( request, sizeof(request), client ); + + HTTPD_DIAG("Request >%s<\n", request ); + + /* Absorb the rest of the header. We nibble it away a + * character at a time like this to avoid having to define + * another buffer to read lines into. If we ever need to take + * more interest in the header fields, we will need to be a + * lot more sophisticated than this. + */ + do{ + int c = getc( client ); + HTTPD_DIAG("%c",c); + if( c == '\n' ) + nlc++; + else if( c != '\r' ) + nlc = 0; + } while(nlc < 2); + + /* Extract the filename and any form data being returned. + * We know that the "GET " request takes 4 bytes. + * TODO: handle POST type requests as well as GET's. + */ + + filename = p = request+4; + + /* Now scan the filename until we hit a space or a '?'. If we + * end on a '?' then the rest is a form request. Put NULs at + * the end of each string. + */ + while( *p != ' ' && *p != '?' ) + p++; + if( *p == '?' ) + formdata = p+1; + *p = 0; + + if( formdata != NULL ) + { + while( *p != ' ' ) + p++; + *p = 0; + } + + HTTPD_DIAG("Request filename >%s< formdata >%s<\n",filename,formdata?formdata:"-NULL-"); + + HTTPD_DIAG("table: %08x...%08x\n",cyg_httpd_table, cyg_httpd_table_end); + + /* Now scan the table for a matching entry. If we find one + * call the handler routine. If that returns true then we + * terminate the scan, otherwise we keep looking. + */ + while( entry != cyg_httpd_table_end ) + { + HTTPD_DIAG("try %08x: %s\n", entry, entry->pattern); + + if( match( filename, entry->pattern ) ) + { + if( (success = entry->handler( client, filename, formdata, entry->arg )) ) + break; + } + + entry++; + } + + /* If we failed to find a match in the table, send a "not + * found" response. + * TODO: add an optional fallback to go look for files in + * some filesystem, somewhere. + */ + if( !success ) + cyg_httpd_send_html( client, NULL, NULL, cyg_httpd_not_found ); + + /* All done, close the connection + */ + err = fclose( client ); + CYG_ASSERT( err == 0, "fclose() returned error"); + + } while(1); +} + +/* ================================================================= */ +/* Initialization thread + * + * Optionally delay for a time before getting the network + * running. Then create and bind the server socket and put it into + * listen mode. Spawn any further server threads, then enter server + * mode. + */ + +static void cyg_httpd_init(cyg_addrword_t arg) +{ + int i; + int err = 0; + + /* Delay for a configurable length of time to give the application + * a chance to get going, or even complete, without interference + * from the HTTPD. + */ + if( CYGNUM_HTTPD_SERVER_DELAY > 0 ) + { + cyg_thread_delay( CYGNUM_HTTPD_SERVER_DELAY ); + } + + server_address.sin_family = AF_INET; + server_address.sin_len = sizeof(server_address); + server_address.sin_addr.s_addr = INADDR_ANY; + server_address.sin_port = htons(CYGNUM_HTTPD_SERVER_PORT); + + /* Get the network going. This is benign if the application has + * already done this. + */ + init_all_network_interfaces(); + + /* Create and bind the server socket. + */ + server_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + CYG_ASSERT( server_socket > 0, "Socket create failed"); + + err = bind( server_socket, (struct sockaddr *)&server_address, + sizeof(server_address) ); + CYG_ASSERT( err == 0, "bind() returned error"); + + err = listen( server_socket, SOMAXCONN ); + CYG_ASSERT( err == 0, "listen() returned error" ); + + /* If we are configured to have more than one server thread, + * create them now. + */ + for( i = 1; i < CYGNUM_HTTPD_THREAD_COUNT; i++ ) + { + cyg_thread_create( CYGNUM_HTTPD_THREAD_PRIORITY, + cyg_httpd_server, + 0, + "HTTPD", + &httpd_stacks[i][0], + sizeof(httpd_stacks[i]), + &httpd_thread[i], + &httpd_thread_object[i] + ); + + cyg_thread_resume( httpd_thread[i] ); + } + + /* Now go be a server ourself. + */ + cyg_httpd_server(arg); +} + +/* ================================================================= */ +/* System initializer + * + * This is called from the static constructor in init.cxx. It spawns + * the main server thread and makes it ready to run. + */ + +__externC void cyg_httpd_startup(void) +{ + cyg_thread_create( CYGNUM_HTTPD_THREAD_PRIORITY, + cyg_httpd_init, + 0, + "HTTPD", + &httpd_stacks[0][0], + sizeof(httpd_stacks[0]), + &httpd_thread[0], + &httpd_thread_object[0] + ); + + cyg_thread_resume( httpd_thread[0] ); +} + +/* ================================================================= */ +/* HTTP protocol handling + * + * cyg_http_start() generates an HTTP header with the given content + * type and, if non-zero, length. + * cyg_http_finish() just adds a couple of newlines for luck and + * flushes the stream. + */ + +__externC void cyg_http_start( FILE *client, char *content_type, + int content_length ) +{ + fputs( "HTTP/1.1 200 OK\n" + "Server: " CYGDAT_HTTPD_SERVER_ID, + client ); + + if( content_type != NULL ) + fprintf( client,"Content-type: %s\n", content_type ); + + if( content_length != 0 ) + fprintf( client, "Content-length: %d\n", content_length ); + + fputs( "Connection: close\n" + "\n", + client ); +} + +__externC void cyg_http_finish( FILE *client ) +{ + fputs( "\n\n", client ); + fflush( client ); +} + + +/* ================================================================= */ +/* HTML tag generation + * + * These functions generate standard HTML begin and end tags. By using + * these rather than direct printf()s we help to reduce the number of + * distinct strings present in the executable. + */ + +__externC void cyg_html_tag_begin( FILE *client, char *tag, char *attr ) +{ + char *pad = ""; + + if( attr == NULL ) + attr = pad; + else if( attr[0] != 0 ) + pad = " "; + + fprintf(client, "<%s%s%s>\n",tag,pad,attr); +} + +__externC void cyg_html_tag_end( FILE *client, char *tag ) +{ + fprintf( client, "<%s%s%s>\n","/",tag,""); +} + +/* ================================================================= */ +/* Parse form request data + * + * Given a form response string, we parse it into an argv/environment + * style array of "name=value" strings. We also convert any '+' + * separators back into spaces. + * + * TODO: also translate any %xx escape sequences back into real + * characters. + */ + +__externC void cyg_formdata_parse( char *data, char *list[], int size ) +{ + char *p = data; + int i = 0; + + list[i] = p; + + while( *p != 0 && i < size-1 ) + { + if( *p == '&' ) + { + *p++ = 0; + list[++i] = p; + continue; + } + if( *p == '+' ) + *p = ' '; + p++; + } + + list[++i] = 0; +} + +/* ----------------------------------------------------------------- */ +/* Search for a form response value + * + * Search a form response list generated by cyg_formdata_parse() for + * the named element. If it is found a pointer to the value part is + * returned. If it is not found a NULL pointer is returned. + */ + +__externC char *cyg_formlist_find( char *list[], char *name ) +{ + while( *list != 0 ) + { + char *p = *list; + char *q = name; + + while( *p == *q ) + p++, q++; + + if( *q == 0 && *p == '=' ) + return p+1; + + list++; + } + + return 0; +} + +/* ================================================================= */ +/* Predefined page handlers + */ + +/* ----------------------------------------------------------------- */ +/* Send an HTML page from a single string + * + * This just sends the string passed as the argument with an HTTP + * header that describes it as HTML. This is useful for sending + * straightforward static web content. + */ + +__externC cyg_bool cyg_httpd_send_html( FILE *client, char *filename, + char *request, void *arg ) +{ + html_begin( client ); + + fwrite( arg, 1, strlen((char *)arg), client ); + + html_end( client ); + + return true; +} + +/* ----------------------------------------------------------------- */ +/* Send arbitrary data + * + * This takes a pointer to a cyg_httpd_data structure as the argument + * and sends the data therein after a header that uses the content + * type and size from the structure. This is useful for non-HTML data + * such a images. + */ + +__externC cyg_bool cyg_httpd_send_data( FILE *client, char *filename, + char *request, void *arg ) +{ + cyg_httpd_data *data = (cyg_httpd_data *)arg; + + cyg_http_start( client, data->content_type, data->content_length ); + + fwrite( data->data, 1, data->content_length, client ); + + return true; +} + +/* ----------------------------------------------------------------- */ +/* end of httpd.c */ diff --git a/packages/net/httpd/current/src/init.cxx b/packages/net/httpd/current/src/init.cxx new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/src/init.cxx @@ -0,0 +1,93 @@ +/* ================================================================= + * + * init.cxx + * + * Constructor for HTTPD + * + * ================================================================= + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating + * System. + * Copyright (C) 2002 Nick Garnett. + * + * eCos is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 or (at your option) + * any later version. + * + * eCos is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with eCos; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or + * use macros or inline functions from this file, or you compile this + * file and link it with other works to produce a work based on this + * file, this file does not by itself cause the resulting work to be + * covered by the GNU General Public License. However the source code + * for this file must still be made available in accordance with + * section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work + * based on this file might be covered by the GNU General Public + * License. + * + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + * ================================================================= + * #####DESCRIPTIONBEGIN#### + * + * Author(s): nickg@calivar.com + * Contributors: nickg@calivar.com + * Date: 2002-10-14 + * Purpose: + * Description: + * + * ####DESCRIPTIONEND#### + * + * ================================================================= + */ + +#include +#include +#include + +#include // tracing macros +#include // assertion macros + +/* ================================================================= */ + +__externC void cyg_httpd_startup(void); + +/* ================================================================= */ +/* Initialization object + */ + +class Cyg_Httpd_Init_Class +{ +public: + Cyg_Httpd_Init_Class(); +}; + +/* ----------------------------------------------------------------- */ +/* Static initialization object instance. The constructor is + * prioritized to run at the same time as any filesystem constructors. + */ +static Cyg_Httpd_Init_Class httpd_initializer CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS); + +/* ----------------------------------------------------------------- */ +/* Constructor, just calls the startup routine. + */ + +Cyg_Httpd_Init_Class::Cyg_Httpd_Init_Class() +{ + cyg_httpd_startup(); +} + +/* ----------------------------------------------------------------- */ +/* end of httpd.c */ diff --git a/packages/net/httpd/current/src/monitor.c b/packages/net/httpd/current/src/monitor.c new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/src/monitor.c @@ -0,0 +1,1483 @@ +/* ================================================================= + * + * monitor.c + * + * An HTTP system monitor + * + * ================================================================= + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating + * System. + * Copyright (C) 2002 Nick Garnett. + * + * eCos is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 or (at your option) + * any later version. + * + * eCos is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with eCos; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or + * use macros or inline functions from this file, or you compile this + * file and link it with other works to produce a work based on this + * file, this file does not by itself cause the resulting work to be + * covered by the GNU General Public License. However the source code + * for this file must still be made available in accordance with + * section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work + * based on this file might be covered by the GNU General Public + * License. + * + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + * ================================================================= + * #####DESCRIPTIONBEGIN#### + * + * Author(s): nickg@calivar.com + * Contributors: nickg@calivar.com + * Date: 2002-10-14 + * Purpose: + * Description: + * + * ####DESCRIPTIONEND#### + * + * ================================================================= + */ + +#include +#include +#include +#include +#include + +#include /* tracing macros */ +#include /* assertion macros */ + +#include + +#include +#ifdef CYGPKG_KERNEL_INSTRUMENT +#include +#include +#endif + +#include +#include + +/* ================================================================= */ +/* Include all the necessary network headers by hand. We need to do + * this so that _KERNEL is correctly defined, or not, for specific + * headers so we can use both the external API and get at internal + * kernel structures. + */ + +#define _KERNEL +#include +#undef _KERNEL +#include +#include +#include +#include + +#define _KERNEL + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ================================================================= */ +/* Use this when a thread appears to have no name. + */ + +#define NULL_THREAD_NAME "----------" + +/* ================================================================= */ +/* Draw navigation bar + * + * This draws a simple table containing links to the various monitor + * pages at the current position in the HTML stream. + */ + +static void draw_navbar( FILE *client ) +{ + html_para_begin( client, "" ); + + html_table_begin( client, "border cellpadding=\"4\"" ); + { + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + html_image( client, "/monitor/ecos.gif", "eCos logo", "" ); + html_table_data_begin( client, "" ); + html_url( client, "Threads", "/monitor/threads.html"); + html_table_data_begin( client, "" ); + html_url( client, "Interrupts", "/monitor/interrupts.html"); + html_table_data_begin( client, "" ); + html_url( client, "Memory", "/monitor/memory.html"); + html_table_data_begin( client, "" ); + html_url( client, "Network", "/monitor/network.html"); +#ifdef CYGPKG_KERNEL_INSTRUMENT + html_table_data_begin( client, "" ); + html_url( client, "Instrumentation", "/monitor/instrument.html"); +#endif + } + html_table_row_end( client ); + } + html_table_end( client ); +} + +/* ================================================================= */ +/* Index page + * + * A simple introductory page matching "/monitor" and + * "/monitor/index.html". + */ + +static char monitor_index_blurb[] = +"

This is the eCos System Monitor. It presents a simple web monitor +and control interface for eCos systems.\n" +"

Use the navigation bar at the bottom of each page to explore." +; + +static cyg_bool cyg_monitor_index( FILE * client, char *filename, + char *formdata, void *arg ) +{ + html_begin(client); + + html_head(client,"eCos System Monitor", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "eCos System Monitor" ); + + fputs( monitor_index_blurb, client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + return 1; +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_entry, + "/monitor", + cyg_monitor_index, + NULL ); + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_index_entry, + "/monitor/index.html", + cyg_monitor_index, + NULL ); + +/* ================================================================= */ +/* Thread Monitor + * + * Uses the kapi thread info API to enumerate all the current threads + * and generate a table showing their state. + */ + +static cyg_bool cyg_monitor_threads( FILE * client, char *filename, + char *formdata, void *arg ) +{ + + html_begin(client); + +/* html_head(client,"Thread Monitor", ""); */ + html_head(client,"eCos Thread Monitor", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "Thread Monitor" ); + + html_table_begin( client, "border" ); + { + cyg_handle_t thread = 0; + cyg_uint16 id = 0; + + html_table_header( client, "Id", "" ); + html_table_header( client, "State", "" ); + html_table_header( client, "Set
Priority", "" ); + html_table_header( client, "Current
Priority", "" ); + html_table_header( client, "Name", "" ); + html_table_header( client, "Stack Base", "" ); + html_table_header( client, "Stack Size", "" ); +#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT + html_table_header( client, "Stack Used", "" ); +#endif + /* Loop over the threads, and generate a table row for + * each. + */ + while( cyg_thread_get_next( &thread, &id ) ) + { + cyg_thread_info info; + char *state_string; + + cyg_thread_get_info( thread, id, &info ); + + if( info.name == NULL ) + info.name = NULL_THREAD_NAME; + + /* Translate the state into a string. + */ + if( info.state == 0 ) + state_string = "RUN"; + else if( info.state & 0x04 ) + state_string = "SUSP"; + else switch( info.state & 0x1b ) + { + case 0x01: state_string = "SLEEP"; break; + case 0x02: state_string = "CNTSLEEP"; break; + case 0x08: state_string = "CREATE"; break; + case 0x10: state_string = "EXIT"; break; + default: state_string = "????"; break; + } + + /* Now generate the row. + */ + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + fprintf( client, "%04x\n", id,id); + html_table_data_begin( client, "" ); + fprintf( client, "%s", state_string); + html_table_data_begin( client, "" ); + fprintf( client, "%d", info.set_pri); + html_table_data_begin( client, "" ); + fprintf( client, "%d", info.cur_pri); + html_table_data_begin( client, "" ); + fputs( info.name, client ); + html_table_data_begin( client, "" ); + fprintf( client, "%08x", info.stack_base ); + html_table_data_begin( client, "" ); + fprintf( client, "%d", info.stack_size ); +#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT + html_table_data_begin( client, "" ); + fprintf( client, "%d", info.stack_used ); +#endif + } + html_table_row_end(client); + + } + } + html_table_end( client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + return 1; +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_show_threads, + "/monitor/threads.htm*", + cyg_monitor_threads, + NULL ); + +/* ================================================================= */ +/* Thread edit page + * + * A page on which the thread's state may be edited. This tests forms + * handling. + */ + +static char thread_edit_blurb[] = +"

This table contains an entry for each property of the thread +that you can edit. The properties are:\n" +"

State: Change thread's state. The Suspend button +will suspend the thread. The Run button will undo any previous +suspends. The Release button will release the thread out of +any sleep it is currently in.\n" +"

Priority: Change the thread's priority.\n" +"

Once the new state has been selected, press the Submit +button to make the change, or Reset to clear it." +; + +static cyg_bool cyg_monitor_thread_edit( FILE * client, char *filename, + char *formdata, void *arg ) +{ + /* If any form data has been supplied, then change the thread's + * state accordingly. + */ + if( formdata != NULL ) + { + char *formlist[6]; + char *state; + char *pri_string; + char *id_string; + cyg_handle_t thread = 0; + cyg_uint16 id; + + /* Parse the data */ + cyg_formdata_parse( formdata, formlist, 6 ); + + /* Get the thread id from the hidden control */ + id_string = cyg_formlist_find( formlist, "thread"); + + sscanf( id_string, "%04hx", &id ); + + thread = cyg_thread_find( id ); + + /* If there is a pri field, change the priority */ + pri_string = cyg_formlist_find( formlist, "pri"); + + if( pri_string != NULL ) + { + cyg_priority_t pri; + + sscanf( pri_string, "%d", &pri ); + + cyg_thread_set_priority( thread, pri ); + } + + /* If there is a state field, change the thread state */ + state = cyg_formlist_find( formlist, "state"); + + if( state != NULL ) + { + if( strcmp( state, "run" ) == 0 ) + cyg_thread_resume( thread ); + if( strcmp( state, "suspend" ) == 0 ) + cyg_thread_suspend( thread ); + if( strcmp( state, "release" ) == 0 ) + cyg_thread_release( thread ); + } + } + + /* Now generate a page showing the current thread state, and + * including form controls to change it. + */ + + html_begin(client); + + html_head(client,"eCos Thread Editor", ""); + + html_body_begin(client,""); + { + cyg_uint16 id; + cyg_thread_info info; + cyg_handle_t thread = 0; + char idbuf[16]; + + sscanf( filename, "/monitor/thread-%04hx.html", &id ); + + thread = cyg_thread_find( id ); + cyg_thread_get_info(thread, id, &info ); + + html_heading(client, 2, "Thread State Editor" ); + + html_para_begin( client, "" ); + + fprintf( client, "Editing Thread %04x %s\n",id, + info.name?info.name:NULL_THREAD_NAME); + + fputs( thread_edit_blurb, client ); + + html_form_begin( client, filename, "" ); + { + html_table_begin( client, "border" ); + { + html_table_header( client, "Property", "" ); + html_table_header( client, "Value", "" ); + + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + fputs( "State", client ); + + html_table_data_begin( client, "" ); + + html_form_input_radio( client, "state", "run", (info.state&0x04)==0 ); + fputs( "Run", client ); + html_form_input_radio( client, "state", "suspend", (info.state&0x04)!=0 ); + fputs( "Suspend", client ); + html_form_input_radio( client, "state", "release", 0 ); + fputs( "Release", client ); + } + html_table_row_end( client ); + + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + fputs( "Priority", client ); + + html_table_data_begin( client, "" ); + fprintf(client,"\n", + info.set_pri); + } + html_table_row_end( client ); + + } + html_table_end( client ); + + /* Add submit and reset buttons */ + html_form_input(client, "submit", "submit", "Submit", ""); + html_form_input(client, "reset", "reset", "Reset", ""); + + /* Pass the thread ID through to our next incarnation */ + sprintf( idbuf, "%04x", id ); + html_form_input_hidden(client, "thread", idbuf ); + + } + html_form_end( client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + return 1; +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_thread_edit_entry, + "/monitor/thread-*", + cyg_monitor_thread_edit, + NULL ); + +/* ================================================================= */ +/* Interrupt monitor + * + * At present this just generates a table showing which interrupts + * have an ISR attached. + */ + +static cyg_bool cyg_monitor_interrupts( FILE * client, char *filename, + char *formdata, void *arg ) +{ + html_begin(client); + + html_head(client,"eCos Interrupt Monitor", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "Interrupt Monitor" ); + + html_table_begin( client, "border" ); + { + int i; + int maxint = CYGNUM_HAL_ISR_MAX; + +#ifdef CYGPKG_HAL_I386 + maxint = CYGNUM_HAL_ISR_MIN+16; +#endif + + html_table_header( client, "ISR", "" ); + html_table_header( client, "State", "" ); + + for( i = CYGNUM_HAL_ISR_MIN; i <= maxint ; i++ ) + { + cyg_bool_t inuse; + HAL_INTERRUPT_IN_USE( i, inuse ); + + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + fprintf( client, "%d", i); + html_table_data_begin( client, "" ); + fprintf( client, "%s", inuse?"In Use":"Free"); + } + html_table_row_end( client ); + } + } + html_table_end( client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + return 1; + +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_interrupts_entry, + "/monitor/interrupts.htm*", + cyg_monitor_interrupts, + NULL ); + +/* ================================================================= */ +/* Memory monitor + * + * Generates a table showing a 256 byte page of memory. Form controls + * allow changes to the base address and display element size. + */ + +static cyg_bool cyg_monitor_memory( FILE * client, char *filename, + char *formdata, void *arg ) +{ + char *formlist[10]; + cyg_uint32 base = 0; + unsigned int datasize = 1; + int size = 256; + char *p; + + cyg_formdata_parse( formdata, formlist, 10 ); + + p = cyg_formlist_find( formlist, "base" ); + + if( p != NULL ) + sscanf( p, "%x", &base ); + + p = cyg_formlist_find( formlist, "datasize" ); + + if( p != NULL ) + sscanf( p, "%x", &datasize ); + + if( cyg_formlist_find( formlist, "next" ) != NULL ) + base += size; + + if( cyg_formlist_find( formlist, "prev" ) != NULL ) + base -= size; + + html_begin(client); + + html_head(client,"eCos Memory Monitor", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "Memory Monitor" ); + + html_form_begin( client, "/monitor/memory.html", "" ); + { + + /* Text input control for base address + */ + html_para_begin( client, "" ); + fprintf(client, + "Base Address: 0x\n", + base); + + /* A little menu for the element size + */ + html_para_begin( client, "" ); + + fputs( "Element Size: ", client ); + html_form_select_begin( client, "datasize", "" ); + html_form_option( client, "1", "bytes", datasize==1 ); + html_form_option( client, "2", "words", datasize==2 ); + html_form_option( client, "4", "dwords", datasize==4 ); + html_form_select_end( client ); + + html_para_begin( client, "" ); + + /* Submit and reset buttons + */ + html_form_input(client, "submit", "submit", "Submit", ""); + html_form_input(client, "reset", "reset", "Reset", ""); + + html_para_begin( client, "" ); + + /* Previous page button */ + html_form_input(client, "submit", "prev", "Prev Page", ""); + + /* Switch to monospaced font */ + cyg_html_tag_begin( client, "font", "face=\"monospace\"" ); + + html_table_begin( client, "" ); + { + cyg_addrword_t loc; + cyg_addrword_t oloc; + + for( oloc = loc = base; loc <= (base+size) ; loc++ ) + { + if( ( loc % 16 ) == 0 ) + { + if( loc != base ) + { + html_table_data_begin( client, "" ); + for( ; oloc < loc; oloc++ ) + { + char c = *(char *)oloc; + if( !isprint(c) ) + c = '.'; + putc( c, client ); + } + html_table_row_end( client ); + } + if( loc == (base+size) ) + break; + html_table_row_begin(client, "" ); + html_table_data_begin( client, "" ); + fprintf( client, "%08x:",loc); + } + + html_table_data_begin( client, "" ); + + if( (loc % datasize) == 0 ) + { + switch( datasize ) + { + case 1: fprintf( client, "%02x", *(cyg_uint8 *)loc ); break; + case 2: fprintf( client, "%04x", *(cyg_uint16 *)loc ); break; + case 4: fprintf( client, "%08x", *(cyg_uint32 *)loc ); break; + } + } + } + } + html_table_end( client ); + cyg_html_tag_end( client, "font" ); + + html_form_input(client, "submit", "next", "Next Page", ""); + } + html_form_end( client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + return 1; + +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_memory_entry, + "/monitor/memory.htm*", + cyg_monitor_memory, + NULL ); + +/* ================================================================= */ +/* Network Monitor + * + * This function generates a page containing information about the + * network interfaces and the protocols. + */ + +static cyg_bool cyg_monitor_network( FILE * client, char *filename, + char *formdata, void *arg ) +{ + struct ifconf ifconf; + char conf[256]; + int err; + int sock; + + /* Start by opening a socket and getting a list of all the + * interfaces present. + */ + { + memset( conf, 0, sizeof(conf) ); + + sock = socket( AF_INET, SOCK_DGRAM, 0 ); + + ifconf.ifc_len = sizeof(conf); + ifconf.ifc_buf = (caddr_t)conf; + + err = ioctl( sock, SIOCGIFCONF, &ifconf ); + } + + html_begin(client); + + html_head(client,"eCos Network Monitor", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "Network Monitor" ); + + html_heading(client, 3, "Interfaces" ); + + html_table_begin( client, "border" ); + { + int i; + struct ifreq *ifrp; + struct sockaddr *sa; + + html_table_header( client, "Interface", "" ); + html_table_header( client, "Status", "" ); + + ifrp = ifconf.ifc_req; + + while( ifconf.ifc_len && ifrp->ifr_name[0] ) + { + struct ifreq ifreq = *ifrp; + + /* For some reason we get two entries for each + * interface in the list: one with an AF_INET address + * and one with an AF_LINK address. We are currently + * only interested in the AF_INET ones. + */ + + if( ifrp->ifr_addr.sa_family == AF_INET ) + { + + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "" ); + fprintf( client, "%s", ifrp->ifr_name); + + html_table_data_begin( client, "" ); + html_table_begin( client, "" ); + { + struct ether_drv_stats ethstats; + + /* Get the interface's flags and display + * the interesting ones. + */ + + if( ioctl( sock, SIOCGIFFLAGS, &ifreq ) >= 0 ) + { + html_table_row_begin(client, "" ); + fprintf( client, "Flags\n" ); + for( i = 0; i < 16; i++ ) + { + switch( ifreq.ifr_flags & (1<= 0 ) + { + struct sockaddr_in *inaddr = + (struct sockaddr_in *)&ifreq.ifr_addr; + + html_table_row_begin(client, "" ); + fprintf( client, "Address%s\n", + inet_ntoa(inaddr->sin_addr)); + html_table_row_end( client ); + } + + /* If there's a netmask, show that. */ + if( ioctl( sock, SIOCGIFNETMASK, &ifreq ) >= 0 ) + { + struct sockaddr_in *inaddr = + (struct sockaddr_in *)&ifreq.ifr_addr; + + html_table_row_begin(client, "" ); + fprintf( client, "Mask%s\n", + inet_ntoa(inaddr->sin_addr)); + html_table_row_end( client ); + } + + /* If there's a broadcast address, show that. */ + if( ioctl( sock, SIOCGIFBRDADDR, &ifreq ) >= 0 ) + { + struct sockaddr_in *inaddr = + (struct sockaddr_in *)&ifreq.ifr_broadaddr; + + html_table_row_begin(client, "" ); + fprintf( client, "Broadcast Address%s\n", + inet_ntoa(inaddr->sin_addr)); + html_table_row_end( client ); + } + + /* If the ethernet driver collects + * statistics, fetch those and show some + * of them. + */ + + ethstats.ifreq = ifreq; + if( ioctl( sock, SIOCGIFSTATS, ðstats ) >= 0 ) + { + fprintf( client, "Hardware%s\n", + ethstats.description ); + fprintf( client, "Packets Received%d\n", + ethstats.rx_count ); + fprintf( client, "Packets Sent%d\n", + ethstats.tx_count ); + fprintf( client, "Interrupts%d\n", + ethstats.interrupts ); + } + } + html_table_end( client ); + } + html_table_row_end( client ); + + } + + /* Scan the addresses, even if we are not interested + * in this interface, since we must skip to the next. + */ + do + { + sa = &ifrp->ifr_addr; + if (sa->sa_len <= sizeof(*sa)) { + ifrp++; + } else { + ifrp=(struct ifreq *)(sa->sa_len + (char *)sa); + ifconf.ifc_len -= sa->sa_len - sizeof(*sa); + } + ifconf.ifc_len -= sizeof(*ifrp); + + } while (!ifrp->ifr_name[0] && ifconf.ifc_len); + } + } + html_table_end( client ); + + /* Now the protocols. For each of the main protocols: IP, + * ICMP, UDP, TCP print a table of useful information derived + * from the in-kernel data structures. Note that this only + * works for the BSD stacks. + */ + + html_para_begin( client, "" ); + html_heading(client, 3, "Protocols" ); + + html_para_begin( client, "" ); + html_table_begin( client, "border"); + { + html_table_header( client, "IP", "" ); + html_table_header( client, "ICMP", "" ); + html_table_header( client, "UDP", "" ); + html_table_header( client, "TCP", "" ); + + html_table_row_begin(client, "" ); + { + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "%s:\n", "Received" ); + fprintf( client, "%s%ld\n", "Total", + ipstat.ips_total ); + fprintf( client, "%s%ld\n", "Bad", + ipstat.ips_badsum+ + ipstat.ips_tooshort+ + ipstat.ips_toosmall+ + ipstat.ips_badhlen+ + ipstat.ips_badlen+ + ipstat.ips_noproto+ + ipstat.ips_toolong + ); + fprintf( client, "%s%ld\n", "Reassembled", + ipstat.ips_reassembled ); + fprintf( client, "%s%ld\n", "Delivered", + ipstat.ips_delivered ); + + fprintf( client, "%s:\n", "Sent" ); + fprintf( client, "%s%ld\n", "Total", + ipstat.ips_localout ); + fprintf( client, "%s%ld\n", "Raw", + ipstat.ips_rawout ); + fprintf( client, "%s%ld\n", "Fragmented", + ipstat.ips_fragmented ); + + } + html_table_end( client ); + + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "%s:\n", "Received" ); + fprintf( client, "%s%ld\n", "ECHO", + icmpstat.icps_inhist[ICMP_ECHO] ); + fprintf( client, "%s%ld\n", "ECHO REPLY", + icmpstat.icps_inhist[ICMP_ECHOREPLY] ); + fprintf( client, "%s%ld\n", "UNREACH", + icmpstat.icps_inhist[ICMP_UNREACH] ); + fprintf( client, "%s%ld\n", "REDIRECT", + icmpstat.icps_inhist[ICMP_REDIRECT] ); + fprintf( client, "%s%ld\n", "Other", + icmpstat.icps_inhist[ICMP_SOURCEQUENCH]+ + icmpstat.icps_inhist[ICMP_ROUTERADVERT]+ + icmpstat.icps_inhist[ICMP_ROUTERSOLICIT]+ + icmpstat.icps_inhist[ICMP_TIMXCEED]+ + icmpstat.icps_inhist[ICMP_PARAMPROB]+ + icmpstat.icps_inhist[ICMP_TSTAMP]+ + icmpstat.icps_inhist[ICMP_TSTAMPREPLY]+ + icmpstat.icps_inhist[ICMP_IREQ]+ + icmpstat.icps_inhist[ICMP_IREQREPLY]+ + icmpstat.icps_inhist[ICMP_MASKREQ]+ + icmpstat.icps_inhist[ICMP_MASKREPLY] + ); + fprintf( client, "%s%ld\n", "Bad", + icmpstat.icps_badcode+ + icmpstat.icps_tooshort+ + icmpstat.icps_checksum+ + icmpstat.icps_badlen+ + icmpstat.icps_bmcastecho + ); + + fprintf( client, "%s:\n", "Sent" ); + fprintf( client, "%s%ld\n", "ECHO", + icmpstat.icps_outhist[ICMP_ECHO] ); + fprintf( client, "%s%ld\n", "ECHO REPLY", + icmpstat.icps_outhist[ICMP_ECHOREPLY] ); + fprintf( client, "%s%ld\n", "UNREACH", + icmpstat.icps_outhist[ICMP_UNREACH] ); + fprintf( client, "%s%ld\n", "REDIRECT", + icmpstat.icps_outhist[ICMP_REDIRECT] ); + fprintf( client, "%s%ld\n", "Other", + icmpstat.icps_inhist[ICMP_SOURCEQUENCH]+ + icmpstat.icps_outhist[ICMP_ROUTERADVERT]+ + icmpstat.icps_outhist[ICMP_ROUTERSOLICIT]+ + icmpstat.icps_outhist[ICMP_TIMXCEED]+ + icmpstat.icps_outhist[ICMP_PARAMPROB]+ + icmpstat.icps_outhist[ICMP_TSTAMP]+ + icmpstat.icps_outhist[ICMP_TSTAMPREPLY]+ + icmpstat.icps_outhist[ICMP_IREQ]+ + icmpstat.icps_outhist[ICMP_IREQREPLY]+ + icmpstat.icps_outhist[ICMP_MASKREQ]+ + icmpstat.icps_outhist[ICMP_MASKREPLY] + ); + } + html_table_end( client ); + + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "%s:\n", "Received" ); + fprintf( client, "%s%ld\n", "Total", + udpstat.udps_ipackets ); + fprintf( client, "%s%ld\n", "Bad", + udpstat.udps_hdrops+ + udpstat.udps_badsum+ + udpstat.udps_badlen+ + udpstat.udps_noport+ + udpstat.udps_noportbcast+ + udpstat.udps_fullsock + ); + fprintf( client, "%s:\n", "Sent" ); + fprintf( client, "%s%ld\n", "Total", + udpstat.udps_opackets ); + } + html_table_end( client ); + + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "%s:\n", "Connections" ); + fprintf( client, "%s%ld\n", "Initiated", + tcpstat.tcps_connattempt ); + fprintf( client, "%s%ld\n", "Accepted", + tcpstat.tcps_accepts ); + fprintf( client, "%s%ld\n", "Established", + tcpstat.tcps_connects ); + fprintf( client, "%s%ld\n", "Closed", + tcpstat.tcps_closed ); + + fprintf( client, "%s:\n", "Received" ); + fprintf( client, "%s%ld\n", "Packets", + tcpstat.tcps_rcvtotal ); + fprintf( client, "%s%ld\n", "Data Packets", + tcpstat.tcps_rcvpack ); + fprintf( client, "%s%ld\n", "Bytes", + tcpstat.tcps_rcvbyte ); + + fprintf( client, "%s:\n", "Sent" ); + fprintf( client, "%s%ld\n", "Packets", + tcpstat.tcps_sndtotal ); + fprintf( client, "%s%ld\n", "Data Packets", + tcpstat.tcps_sndpack ); + fprintf( client, "%s%ld\n", "Bytes", + tcpstat.tcps_sndbyte ); + + + } + html_table_end( client ); + + + } + html_table_row_end( client ); + + } + html_table_end( client ); + + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + close( sock ); + + return 1; + +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_network_entry, + "/monitor/network.htm*", + cyg_monitor_network, + NULL ); + + +/* ================================================================= */ +/* Instrumentation Monitor + * + * If the CYGPKG_KERNEL_INSTRUMENT option is set, we generate a table + * showing the current instrumentation buffer. If the FLAGS option is + * enabled we also print a table giving control of the flags. + * + */ + +#ifdef CYGPKG_KERNEL_INSTRUMENT + +/* Instrumentation record. */ +struct Instrument_Record +{ + CYG_WORD16 type; // record type + CYG_WORD16 thread; // current thread id + CYG_WORD timestamp; // 32 bit timestamp + CYG_WORD arg1; // first arg + CYG_WORD arg2; // second arg +}; +typedef struct Instrument_Record Instrument_Record; + +/* Instrumentation variables, these live in the + * instrumentation files in the kernel + */ +__externC Instrument_Record *instrument_buffer_pointer; +__externC Instrument_Record instrument_buffer[]; +__externC cyg_uint32 instrument_buffer_size; + +#if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ + defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + +static cyg_uint32 instrument_flags[(CYG_INSTRUMENT_CLASS_MAX>>8)+1]; + +#endif + +static char cyg_monitor_instrument_blurb1[] = +"

Use the checkboxes to enable the events to be recorded. Click +the Submit button to start recording. Click the Clear +button to clear all instrumentation and to stop recording." +; + +static cyg_bool cyg_monitor_instrument( FILE * client, char *filename, + char *formdata, void *arg ) +{ + +#if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ + defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + + /* Disable all instrumentation while we generate the page. + * Otherwise we could swamp the information we are really after. + */ + + cyg_scheduler_lock(); + { + struct instrument_desc_s *id = instrument_desc; + CYG_WORD cl = 0, ev = 0; + + for( ; id->msg != 0; id++ ) + { + if( id->num > 0xff ) + { + cl = id->num>>8; + instrument_flags[cl] = 0; + } + else + { + ev = id->num; + cyg_instrument_disable( cl<<8, ev ); + } + } + } + cyg_scheduler_unlock(); + +#endif + + /* If we have some form data, deal with it. + */ + if( formdata != NULL ) + { + char *list[40]; + + cyg_formdata_parse( formdata, list, sizeof(list)/sizeof(*list) ); + +#if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ + defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + + if( cyg_formlist_find( list, "clear" ) != NULL ) + { + /* If the clear button is set, then disable all instrumentation flags. + */ + int i; + for( i = 0; i < sizeof(instrument_flags)/sizeof(*instrument_flags); i++ ) + instrument_flags[i] = 0; + } + else + { + /* Otherwise all the set checkboxes have been reported to + * us in the form of class=event inputs. + */ + char **p; + for( p = list; *p != NULL; p++ ) + { + int cl,ev; + if( sscanf( *p, "%02x=%02x", &cl, &ev ) == 2 ) + instrument_flags[cl] |= 1<type = 0; + ibp++; + if( ibp == &instrument_buffer[instrument_buffer_size] ) + ibp = instrument_buffer; + + } while( ibp != instrument_buffer_pointer ); + + } + cyg_scheduler_unlock(); + } + } + + /* Now start generating the HTML page. + */ + html_begin(client); + + html_head(client,"eCos Instrumentation Buffer", ""); + + html_body_begin(client,""); + { + html_heading(client, 2, "Instrumentation Buffer" ); + + html_form_begin( client, "/monitor/instrument.html", "" ); + +#if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ + defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + + /* If we have the flags enabled, generate a table showing all + * the flag names with a checkbox against each. + */ + + fputs( cyg_monitor_instrument_blurb1, client ); + + html_para_begin( client, "" ); + /* Add submit,clear and reset buttons */ + html_form_input(client, "submit", "submit", "Submit", ""); + html_form_input(client, "submit", "clear", "Clear", ""); + html_form_input(client, "reset", "reset", "Reset", ""); + + html_table_begin( client, "border width=100%" ); + { + struct instrument_desc_s *id = instrument_desc; + CYG_WORD cl = 0, ev = 0; + int clc = 0; + char class[5], event[5]; + + html_table_row_begin( client, "" ); + + for( ; id->msg != 0; id++ ) + { + if( id->num > 0xff ) + { + cl = id->num; + sprintf( class, "%02x", cl>>8 ); + clc = 0; + + if( id != instrument_desc ) + { + html_table_end( client ); + html_table_row_end( client ); + html_table_row_begin( client, "" ); + } + + html_table_data_begin( client, "valign=\"top\" width=100%" ); + html_table_begin( client, "width=100%" ); + } + else + { + ev = id->num; + sprintf( event, "%02x", ev ); + + if( (clc%4) == 0 ) + { + if( clc != 0 ) + html_table_row_end( client ); + + html_table_row_begin( client, "" ); + } + clc++; + html_table_data_begin( client, "width=25%" ); + html_form_input_checkbox( client, class, event, + instrument_flags[cl>>8] & (1<msg, client ); + } + } + html_table_end( client ); + html_table_row_end( client ); + } + html_table_end( client ); + + /* Add submit,clear and reset buttons */ + html_form_input(client, "submit", "submit", "Submit", ""); + html_form_input(client, "submit", "clear", "Clear", ""); + html_form_input(client, "reset", "reset", "Reset", ""); + +#endif + + html_para_begin( client, "" ); + + html_form_input(client, "submit", "cleartable", "Clear Table", ""); + + + /* + */ + + html_table_begin( client, "border" ); + { + Instrument_Record *ibp = instrument_buffer_pointer; + + html_table_header( client, "TIME", "" ); + html_table_header( client, "THREAD", "" ); + html_table_header( client, "EVENT", "" ); + html_table_header( client, "ARG1", "" ); + html_table_header( client, "ARG2", "" ); + + do + { + if( ibp->type != 0 ) + { + html_table_row_begin(client, "" ); + { + cyg_handle_t thread = cyg_thread_find(ibp->thread); + cyg_thread_info info; + + html_table_data_begin( client, "" ); + fprintf( client, "%08x",ibp->timestamp); + html_table_data_begin( client, "" ); + if( thread != 0 && + cyg_thread_get_info( thread, ibp->thread, &info ) && + info.name != NULL ) + fputs( info.name, client ); + else fprintf( client, "[%04x]", ibp->thread); + html_table_data_begin( client, "" ); +#if defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + fprintf( client, "%s", cyg_instrument_msg(ibp->type)); +#else + fprintf( client, "%04x", ibp->type ); +#endif + html_table_data_begin( client, "" ); + fprintf( client, "%08x", ibp->arg1); + html_table_data_begin( client, "" ); + fprintf( client, "%08x", ibp->arg2); + } + html_table_row_end( client ); + } + ibp++; + if( ibp == &instrument_buffer[instrument_buffer_size] ) + ibp = instrument_buffer; + + } while( ibp != instrument_buffer_pointer ); + } + html_table_end( client ); + + html_para_begin( client, "" ); + + html_form_input(client, "submit", "cleartable", "Clear Table", ""); + + html_form_end( client ); + + draw_navbar(client); + } + html_body_end(client); + + html_end(client); + + +#if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ + defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) + + /* + */ + + cyg_scheduler_lock(); + { + struct instrument_desc_s *id = instrument_desc; + CYG_WORD cl = 0, ev = 0; + + for( ; id->msg != 0; id++ ) + { + if( id->num > 0xff ) + cl = id->num>>8; + else + { + ev = id->num; + if( (instrument_flags[cl] & (1<