Mercurial > ecos
changeset 468:ca4f29d41b18
Created new HTTPD package.
| author | nickg |
|---|---|
| date | Sun, 22 Dec 2002 11:09:00 +0000 |
| parents | a358ddc533a1 |
| children | f8c4a9e9a26e |
| files | packages/net/httpd/current/ChangeLog packages/net/httpd/current/cdl/httpd.cdl packages/net/httpd/current/doc/httpd.sgml packages/net/httpd/current/include/httpd.h packages/net/httpd/current/src/httpd.c packages/net/httpd/current/src/init.cxx packages/net/httpd/current/src/monitor.c |
| diffstat | 7 files changed, 3106 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/ChangeLog @@ -0,0 +1,16 @@ +2002-12-06 Nick Garnett <nickg@ecoscentric.com> + + * 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
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
new file mode 100644 --- /dev/null +++ b/packages/net/httpd/current/doc/httpd.sgml @@ -0,0 +1,532 @@ + +<!-- =============================================================== --> +<!-- --> +<!-- httpd.sgml --> +<!-- --> +<!-- eCos HTTP Server --> +<!-- --> +<!-- =============================================================== --> +<!-- ####COPYRIGHTBEGIN#### --> +<!-- --> +<!-- =============================================================== --> +<!-- Copyright (C) 2002 Nick Garnett --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- --> +<!-- ####COPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<part id="net-httpd"> +<title>Embedded HTTP Server</title> +<chapter id="net-httpd-chapter"> +<title>Embedded HTTP Server</title> + +<sect1 id="net-httpd-intro"> +<title>Intrduction</title> +<para> +The <emphasis>eCos</emphasis> 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 +<emphasis>not</emphasis> 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 <ulink +url="www.goahead.com">www.goahead.com</ulink>. +</para> +</sect1> + +<sect1 id="net-httpd-organization"> +<title>Server Organization</title> +<para> +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. +</para> +<para> +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 <function>cyg_scheduler_start()</function>. +</para> +<para> +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. +</para> +<para> +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. +</para> +<para> +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 <literal>CYG_HTTPD_TABLE_ENTRY()</literal> macro which has the +following format: +</para> +<programlisting width=72> + +#include <cyg/httpd/httpd.h> + +CYG_HTTPD_TABLE_ENTRY( __name, __pattern, __handler, __arg ) + +</programlisting> +<para> +The <parameter>__name</parameter> 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 <parameter>__pattern</parameter> +argument is the match pattern. The <parameter>__handler</parameter> +argument is a pointer to the handler function and +<parameter>__arg</parameter> the user defined value. +</para> +<para> +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. +</para> +<para> +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-". +</para> +<para> +When a pattern is matched, the hander function is called. It has the +following prototype: +</para> +<programlisting width=72> +cyg_bool cyg_httpd_handler(FILE *client, + char *filename, + char *formdata, + void *arg); +</programlisting> +<para> +The <parameter>client</parameter> argument is the TCP connection to +the client: anything output through this stream will be returned to +the browser. The <parameter>filename</parameter> argument is the +filename from the HTTP request and the <parameter>formdata</parameter> +argument is any form response data, or NULL if none was sent. The +<parameter>arg</parameter> argument is the user defined value from the +table entry. +</para> +<para> +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 +<literal>false</literal>, 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. +</para> +<para> +Finally, the server thread closes the connection to the client and +loops back to accept a new connection. +</para> +</sect1> + +<!-- =============================================================== --> + +<sect1 id="net-httpd-configuration"> +<title>Server Configuration</title> +<para> +The HTTP server has a number of configuration options: +</para> + +<sect2> +<title><literal>CYGNUM_HTTPD_SERVER_PORT</literal></title> +<para> +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. +</para> +</sect2> + +<sect2> +<title><literal>CYGDAT_HTTPD_SERVER_ID</literal></title> +<para> +This is the string that is reported to the client in the +"Server:" field of the HTTP header. +</para> +</sect2> + +<sect2> +<title><literal>CYGNUM_HTTPD_THREAD_COUNT</literal></title> +<para> +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. +</para> +</sect2> + +<sect2> +<title><literal>CYGNUM_HTTPD_THREAD_PRIORITY</literal></title> +<para> +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. +</para> +</sect2> + +<sect2> +<title><literal>CYGNUM_HTTPD_THREAD_STACK_SIZE</literal></title> +<para> +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 <literal>CYGNUM_HAL_STACK_SIZE_MINIMUM</literal> and +<literal>CYGNUM_HTTPD_SERVER_BUFFER_SIZE</literal>. +</para> +</sect2> + +<sect2> +<title><literal>CYGNUM_HTTPD_SERVER_BUFFER_SIZE</literal></title> +<para> +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. +</para> +</sect2> + +<sect2> +<title><literal>CYGNUM_HTTPD_SERVER_DELAY</literal></title> +<para> +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. +</para> +</sect2> + +</sect1> + +<!-- =============================================================== --> + +<sect1 id="net-httpd-html"> +<title>Support Functions and Macros</title> +<para> +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 <function>fprintf()</function> and +<function>fputs()</function>. 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. +</para> +<para> +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 +<filename>cyg/httpd/httpd.h</filename> header file defines a set of +helper functions and macros. Most of these are wrappers for predefined +print calls on the <parameter>client</parameter> stream passed to the +hander function. For examples of their use, see the System Monitor +example. +</para> +<note> +<para> +All arguments to macros are pointers to strings, unless otherwise +stated. In general, wherever a function or macro has an +<parameter>attr</parameter> or <parameter>__attr</parameter> +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. +</para> +</note> + +<sect2> +<title>HTTP Support</title> +<programlisting width=72> +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 ) +</programlisting> +<para> +The function <function>cyg_http_start()</function> generates a simple +HTTP response header containing the value of +<literal>CYGDAT_HTTPD_SERVER_ID</literal> in the "Server" field, and the +values of <parameter>content_type</parameter> and +<parameter>content_length</parameter> in the "Content-type" +and "Content-length" field respectively. The function +<function>cyg_http_finish()</function> just adds an extra newline to +the end of the output and then flushes it to force the data out to the +client. +</para> +<para> +The macro <literal>html_begin()</literal> generates an HTTP header +with a "text/html" content type followed by an opening +"<html>" tag. <literal>html_end()</literal> generates +a closing "</html>" tag and calls +<function>cyg_http_finish()</function>. +</para> +</sect2> + +<sect2> +<title>General HTML Support</title> +<programlisting width=72> +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 ) +</programlisting> +<para> +The function <function>cyg_html_tag_begin()</function> generates an +opening tag with the given name. The function +<function>cyg_html_tag_end()</function> generates a closing tag with +the given name. The macros <literal>html_tag_begin()</literal> and +<literal>html_tag_end</literal> are just wrappers for these functions. +</para> +<para> +The macro <literal>html_head()</literal> generates an HTML header +section with <parameter>__title</parameter> as the title. The +<parameter>__meta</parameter> argument defines any meta tags that will +be inserted into the header. <literal>html_body_begin()</literal> and +<literal>html_body_end</literal> generate HTML body begin and end +tags. +</para> +<para> +<literal>html_heading()</literal> generates a complete HTML header +where <parameter>__level</parameter> is a numerical level, between 1 +and 6, and <parameter>__heading</parameter> is the heading +text. <literal>html_para_begin()</literal> generates a paragraph +break. +</para> +<para> +<literal>html_url()</literal> inserts a URL where +<parameter>__text</parameter> is the displayed text and +<parameter>__link</parameter> is the URL of the linked +page. <literal>html_image()</literal> inserts an image tag where +<parameter>__source</parameter> is the URL of the image to be +included and <parameter>__alt</parameter> is the alternative text for +when the image is not displayed. +</para> +</sect2> + +<sect2> +<title>Table Support</title> +<programlisting width=72> +#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 ) +</programlisting> +<para> +<literal>html_table_begin()</literal> starts a table and +<literal>html_table_end()</literal> end +it. <literal>html_table_header()</literal> generates a simple table +column header containg the string <parameter>__content</parameter>. +</para> +<para> +<literal>html_table_row_begin()</literal> and +<literal>html_table_row_end()</literal> begin and end a table row, +and similarly <literal>html_table_data_begin()</literal> and +<literal>html_table_data_end()</literal> begin and end a table +entry. +</para> +</sect2> + +<sect2> +<title>Forms Support</title> +<programlisting width=72> +#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 ); +</programlisting> +<para> +<literal>html_form_begin()</literal> begins a form, the +<parameter>__url</parameter> argument is the value for the +<literal>action</literal> +attribute. <literal>html_form_end()</literal> ends the form. +</para> +<para> +<literal>html_form_input()</literal> defines a general form input +element with the given type, name and +value. <literal>html_form_input_radio</literal> creates a radio button +with the given name and value; the <parameter>__checked</parameter> +argument is a boolean expression that is used to determine whether the +<literal>checked</literal> attribute is added to the tag. Similarly +<literal>html_form_input_checkbox()</literal> defines a checkbox +element. <literal>html_form_input_hidden()</literal> defines a hidden +form element with the given name and value. +</para> +<para> +<literal>html_form_select_begin()</literal> begins a multiple choice +menu with the given name. <literal>html_form_select_end()</literal> +end it. <literal>html_form_option()</literal> defines a menu entry +with the given value and label; the <parameter>__selected</parameter> +argument is a boolean expression controlling whether the +<literal>selected</literal> attribute is added to the tag. +</para> +<para> +<function>cyg_formdata_parse()</function> converts a form response +string into an <literal>NULL</literal>-terminated array of +"name=value" entries. The <parameter>data</parameter> +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. <parameter>list</parameter> is a pointer to an array of +character pointers, and is <parameter>size</parameter> elements long. +<function>cyg_formlist_find()</function> searches a list generated by +<function>cyg_formdata_parse()</function> and returns a pointer to the +value part of the string whose name part matches +<parameter>name</parameter>; if there is no match it will return +<literal>NULL</literal>. +</para> +</sect2> + +<sect2> +<title>Predefined Handlers</title> +<programlisting width=72> + +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 ); + +</programlisting> +<para> +The HTTP server defines a couple of predefined handers to make it +easier to deliver simple, static content. +</para> +<para> +<function>cyg_httpd_send_html()</function> takes a +<literal>NULL</literal>-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: +</para> +<programlisting width=72> + +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 ); + +</programlisting> +<para> +<function>cyg_httpd_send_data()</function> Sends arbitrary data to the +client. The argument is a pointer to a <type>cyg_httpd_data</type> +structure that defines the content type and length of the data, and a +pointer to the data itself. The <literal>CYG_HTTPD_DATA()</literal> +macro automates the definition of the structure. Here is a typical +example of its use: +</para> +<programlisting width=72> + +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 ); + +</programlisting> +</sect2> + +</sect1> + +<!-- =============================================================== --> + +<sect1 id="net-httpd-monitor"> +<title>System Monitor</title> +<para> +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. +</para> +<para> +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 <literal>CYGPKG_HTTPD_MONITOR</literal> option. +</para> +<para> +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. +</para> +</sect1> + +<!-- =============================================================== --> + +</chapter> +</part>
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 <pkgconf/system.h> +#include <pkgconf/isoinfra.h> +#include <pkgconf/httpd.h> + +#include <cyg/hal/hal_tables.h> + +#include <stdio.h> + +/* ================================================================= */ +/* 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>%s</%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,"<h%d>%s</h%d>\n",__level,__heading,__level); + +/* ----------------------------------------------------------------- */ +/* + */ + + +#define html_url( __client, __text, __link ) \ + fprintf( __client, "<a href=\"%s\">%s</a>\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 */
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 <pkgconf/system.h> +#include <pkgconf/isoinfra.h> +#include <pkgconf/httpd.h> + +#include <cyg/infra/cyg_trac.h> /* tracing macros */ +#include <cyg/infra/cyg_ass.h> /* assertion macros */ + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include <network.h> +#include <arpa/inet.h> + +#include <cyg/httpd/httpd.h> + +/* ================================================================= */ + +#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[] = +"<head><title>Page Not found</title></head>\n" +"<body><h2>The requested URL was not found on this server.</h2></body>\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 */
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 <pkgconf/system.h> +#include <pkgconf/isoinfra.h> +#include <pkgconf/httpd.h> + +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // 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 */
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 <pkgconf/system.h> +#include <pkgconf/isoinfra.h> +#include <pkgconf/net.h> +#include <pkgconf/httpd.h> +#include <pkgconf/kernel.h> + +#include <cyg/infra/cyg_trac.h> /* tracing macros */ +#include <cyg/infra/cyg_ass.h> /* assertion macros */ + +#include <cyg/httpd/httpd.h> + +#include <cyg/kernel/kapi.h> +#ifdef CYGPKG_KERNEL_INSTRUMENT +#include <cyg/kernel/instrmnt.h> +#include <cyg/kernel/instrument_desc.h> +#endif + +#include <unistd.h> +#include <ctype.h> + +/* ================================================================= */ +/* 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 <sys/param.h> +#undef _KERNEL +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/time.h> + +#define _KERNEL + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <sys/protosw.h> +#include <netinet/in_pcb.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> +#include <netinet/tcp_timer.h> +#include <netinet/ip_var.h> +#include <netinet/icmp_var.h> +#include <netinet/udp_var.h> +#include <netinet/tcp_var.h> + +#include <cyg/io/eth/eth_drv_stats.h> + +/* ================================================================= */ +/* 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[] = +"<p>This is the eCos System Monitor. It presents a simple web monitor +and control interface for eCos systems.\n" +"<p>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", "<meta http-equiv=\"refresh\" content=\"10\">"); */ + 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<br>Priority", "" ); + html_table_header( client, "Current<br>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, "<a href=\"/monitor/thread-%04x.html\">%04x</a>\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[] = +"<p>This table contains an entry for each property of the thread +that you can edit. The properties are:\n" +"<p><b>State:</b> Change thread's state. The <em>Suspend</em> button +will suspend the thread. The <em>Run</em> button will undo any previous +suspends. The <em>Release</em> button will release the thread out of +any sleep it is currently in.\n" +"<p><b>Priority:</b> Change the thread's priority.\n" +"<p>Once the new state has been selected, press the <em>Submit</em> +button to make the change, or <em>Reset</em> 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,"<input type=\"text\" name=\"pri\" size=\"10\" value=\"%d\">\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<input type=\"text\" name=\"base\" size=\"10\" value=\"%x\">\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, "<td>Flags<td>\n" ); + for( i = 0; i < 16; i++ ) + { + switch( ifreq.ifr_flags & (1<<i) ) + { + default: break; + case IFF_UP: fputs( " UP", client ); break; + case IFF_BROADCAST: fputs( " BROADCAST", client ); break; + case IFF_DEBUG: fputs( " DEBUG", client ); break; + case IFF_LOOPBACK: fputs( " LOOPBACK", client ); break; + case IFF_PROMISC: fputs( " PROMISCUOUS", client ); break; + case IFF_RUNNING: fputs( " RUNNING", client ); break; + case IFF_SIMPLEX: fputs( " SIMPLEX", client ); break; + case IFF_MULTICAST: fputs( " MULTICAST", client ); break; + } + } + html_table_row_end( client ); + } + + /* Get the interface's address and display it. */ + if( ioctl( sock, SIOCGIFADDR, &ifreq ) >= 0 ) + { + struct sockaddr_in *inaddr = + (struct sockaddr_in *)&ifreq.ifr_addr; + + html_table_row_begin(client, "" ); + fprintf( client, "<td>Address<td>%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, "<td>Mask<td>%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, "<td>Broadcast Address<td>%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, "<tr><td>Hardware<td>%s</tr>\n", + ethstats.description ); + fprintf( client, "<tr><td>Packets Received<td>%d</tr>\n", + ethstats.rx_count ); + fprintf( client, "<tr><td>Packets Sent<td>%d</tr>\n", + ethstats.tx_count ); + fprintf( client, "<tr><td>Interrupts<td>%d</tr>\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, "<tr><td><b>%s:</b><td></tr>\n", "Received" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Total", + ipstat.ips_total ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\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, "<tr><td>%s<td>%ld</tr>\n", "Reassembled", + ipstat.ips_reassembled ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Delivered", + ipstat.ips_delivered ); + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Sent" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Total", + ipstat.ips_localout ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Raw", + ipstat.ips_rawout ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Fragmented", + ipstat.ips_fragmented ); + + } + html_table_end( client ); + + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Received" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "ECHO", + icmpstat.icps_inhist[ICMP_ECHO] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "ECHO REPLY", + icmpstat.icps_inhist[ICMP_ECHOREPLY] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "UNREACH", + icmpstat.icps_inhist[ICMP_UNREACH] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "REDIRECT", + icmpstat.icps_inhist[ICMP_REDIRECT] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\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, "<tr><td>%s<td>%ld</tr>\n", "Bad", + icmpstat.icps_badcode+ + icmpstat.icps_tooshort+ + icmpstat.icps_checksum+ + icmpstat.icps_badlen+ + icmpstat.icps_bmcastecho + ); + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Sent" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "ECHO", + icmpstat.icps_outhist[ICMP_ECHO] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "ECHO REPLY", + icmpstat.icps_outhist[ICMP_ECHOREPLY] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "UNREACH", + icmpstat.icps_outhist[ICMP_UNREACH] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "REDIRECT", + icmpstat.icps_outhist[ICMP_REDIRECT] ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\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, "<tr><td><b>%s:</b><td></tr>\n", "Received" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Total", + udpstat.udps_ipackets ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Bad", + udpstat.udps_hdrops+ + udpstat.udps_badsum+ + udpstat.udps_badlen+ + udpstat.udps_noport+ + udpstat.udps_noportbcast+ + udpstat.udps_fullsock + ); + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Sent" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Total", + udpstat.udps_opackets ); + } + html_table_end( client ); + + html_table_data_begin( client, "valign=\"top\"" ); + html_table_begin( client, "" ); + { + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Connections" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Initiated", + tcpstat.tcps_connattempt ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Accepted", + tcpstat.tcps_accepts ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Established", + tcpstat.tcps_connects ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Closed", + tcpstat.tcps_closed ); + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Received" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Packets", + tcpstat.tcps_rcvtotal ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Data Packets", + tcpstat.tcps_rcvpack ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Bytes", + tcpstat.tcps_rcvbyte ); + + fprintf( client, "<tr><td><b>%s:</b><td></tr>\n", "Sent" ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Packets", + tcpstat.tcps_sndtotal ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\n", "Data Packets", + tcpstat.tcps_sndpack ); + fprintf( client, "<tr><td>%s<td>%ld</tr>\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[] = +"<p>Use the checkboxes to enable the events to be recorded. Click +the <em>Submit</em> button to start recording. Click the <em>Clear</em> +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<<ev; + } + } +#endif + + /* If the cleartable button has been pressed, clear all the + * table entries. + */ + if( cyg_formlist_find( list, "cleartable" ) != NULL ) + { + cyg_scheduler_lock(); + { + Instrument_Record *ibp = instrument_buffer_pointer; + do + { + ibp->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<<ev) ); + fputs( id->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<<ev)) != 0 ) + cyg_instrument_enable( cl<<8, ev ); + } + } + } + cyg_scheduler_unlock(); +#endif + + return true; +} + +CYG_HTTPD_TABLE_ENTRY( cyg_monitor_instrument_entry, + "/monitor/instrument.htm*", + cyg_monitor_instrument, + NULL ); + +#endif + +/* ================================================================= */ +/* eCos Logo + * + * Define the logo as a byte array, and then define the data structure + * and table entry to allow it to be fetched by the client. + */ + +static cyg_uint8 ecos_logo_gif[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x6f, 0x00, 0x23, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xea, 0x19, 0x00, 0xcc, 0x00, 0x00, 0xfd, 0xfd, 0xfd, 0x83, 0x00, 0x00, 0xf6, + 0xf6, 0xf6, 0x2f, 0x2f, 0x2f, 0xef, 0xef, 0xef, 0x19, 0x00, 0x19, 0x45, 0x45, 0x45, 0xbb, 0xbb, + 0xbb, 0xe2, 0x3e, 0x3e, 0xe8, 0xbb, 0xd3, 0x3e, 0x3e, 0x3e, 0xfb, 0xfb, 0xfb, 0xbe, 0xbe, 0xbe, + 0xf1, 0xed, 0xed, 0xe5, 0x7b, 0x8e, 0xe5, 0x6b, 0x7b, 0xcc, 0xcc, 0xcc, 0x98, 0x95, 0x98, 0xc6, + 0xc3, 0xc6, 0x19, 0x19, 0x19, 0xf1, 0xf1, 0xf1, 0x98, 0x98, 0x98, 0xd6, 0xd3, 0xd6, 0x83, 0x83, + 0x83, 0xde, 0xde, 0xde, 0xe5, 0x25, 0x25, 0x73, 0x6f, 0x73, 0xea, 0xea, 0xea, 0xe5, 0x8e, 0xa2, + 0xe8, 0xe8, 0xe8, 0x7f, 0x7b, 0x7f, 0xe2, 0x56, 0x66, 0x8b, 0x8b, 0x8b, 0x19, 0x19, 0x00, 0xf8, + 0xf8, 0xf8, 0x73, 0x73, 0x73, 0xd3, 0xd1, 0xd1, 0x9c, 0x9c, 0x9c, 0x50, 0x50, 0x50, 0xef, 0xce, + 0xea, 0x92, 0x8e, 0x92, 0x6f, 0x6f, 0x6f, 0xe2, 0x2f, 0x2f, 0x61, 0x61, 0x61, 0xe5, 0xe5, 0xe5, + 0xe8, 0x9f, 0xb8, 0x37, 0x2f, 0x37, 0x66, 0x66, 0x66, 0xe2, 0x4b, 0x50, 0x56, 0x50, 0x56, 0xa9, + 0xa5, 0xa9, 0xce, 0xce, 0xce, 0x56, 0x50, 0x50, 0xd9, 0xd9, 0xd9, 0x77, 0x73, 0x77, 0x25, 0x25, + 0x2f, 0x6b, 0x6b, 0x6b, 0x9f, 0x9f, 0x9f, 0x87, 0x83, 0x87, 0x3e, 0x37, 0x37, 0xf4, 0xf4, 0xf4, + 0x25, 0x25, 0x25, 0xc1, 0xc1, 0xc1, 0x83, 0x7f, 0x83, 0xe5, 0xe2, 0xe2, 0x4b, 0x45, 0x4b, 0xd1, + 0xce, 0xd1, 0xaf, 0xac, 0xaf, 0xcc, 0xc9, 0xcc, 0x5b, 0x56, 0x5b, 0xdb, 0xd9, 0xdb, 0x66, 0x61, + 0x66, 0xe2, 0xe2, 0xe2, 0xb8, 0xb5, 0xb8, 0x2f, 0x25, 0x2f, 0xc3, 0xc1, 0xc3, 0xe0, 0xde, 0xe0, + 0xd3, 0xd3, 0xd3, 0xde, 0xdb, 0xde, 0xac, 0xac, 0xac, 0xce, 0xcc, 0xce, 0x77, 0x6f, 0x73, 0x4b, + 0x45, 0x45, 0xc9, 0xc6, 0xc9, 0x45, 0x3e, 0x45, 0x61, 0x5b, 0x61, 0xb5, 0xb2, 0xb5, 0x3e, 0x00, + 0x00, 0x8b, 0x87, 0x87, 0x95, 0x92, 0x95, 0xa2, 0x9f, 0xa2, 0xb8, 0xb8, 0xb8, 0x7b, 0x77, 0x7b, + 0x9c, 0x98, 0x9c, 0x50, 0x4b, 0x50, 0x6f, 0x6b, 0x6f, 0x6b, 0x66, 0x6b, 0xac, 0xa9, 0xac, 0x8e, + 0x8b, 0x8e, 0x8e, 0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xed, 0xed, 0xed, 0x50, 0x4b, 0x4b, 0x3e, 0x37, + 0x3e, 0x95, 0x95, 0x95, 0xa5, 0xa2, 0xa5, 0x9f, 0x9c, 0x9f, 0xc1, 0xbe, 0xbe, 0x2f, 0x25, 0x25, + 0xd3, 0xd1, 0xd3, 0xf4, 0xf1, 0xf4, 0xc6, 0xc6, 0xc6, 0x8e, 0x8e, 0x8e, 0x25, 0x19, 0x19, 0x66, + 0x61, 0x61, 0xb2, 0xaf, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x6f, 0x00, 0x23, 0x00, 0x40, 0x08, 0xff, 0x00, 0x03, 0x08, 0x1c, 0x28, 0x10, 0x41, + 0x8a, 0x17, 0x0e, 0x1c, 0x00, 0x58, 0xc8, 0xb0, 0xa1, 0xc3, 0x87, 0x10, 0x21, 0x12, 0x14, 0x28, + 0xa0, 0xa2, 0xc5, 0x8b, 0x18, 0x33, 0x6a, 0xdc, 0xb8, 0x91, 0x01, 0x83, 0x11, 0x31, 0x26, 0x12, + 0x44, 0x10, 0x91, 0xe1, 0x09, 0x91, 0x28, 0x03, 0x4c, 0xb9, 0x50, 0x72, 0xa1, 0x0a, 0x04, 0x29, + 0x09, 0x72, 0x6c, 0x10, 0x73, 0xe2, 0x88, 0x8d, 0x2e, 0x0c, 0xd4, 0x0c, 0x70, 0x73, 0x63, 0x80, + 0x88, 0x10, 0x76, 0x0a, 0x6d, 0x18, 0x94, 0x60, 0x03, 0x8e, 0x1a, 0x27, 0x4a, 0x40, 0x5a, 0x51, + 0xa9, 0xc5, 0x0e, 0x3b, 0x0d, 0x30, 0x40, 0xca, 0x40, 0x45, 0xc9, 0x14, 0x42, 0x45, 0x72, 0x60, + 0xf9, 0xf0, 0x64, 0xd6, 0x00, 0x19, 0x3b, 0xe8, 0xfc, 0x3a, 0x70, 0xe9, 0x45, 0x10, 0x59, 0x0d, + 0x70, 0x9c, 0x30, 0xf1, 0x44, 0xcb, 0xb7, 0x70, 0x4b, 0x8a, 0x64, 0x4a, 0xb7, 0xae, 0x5d, 0x01, + 0x6c, 0x51, 0xbe, 0x88, 0xcb, 0xb7, 0xef, 0xc2, 0xb9, 0x77, 0x03, 0x0b, 0xbe, 0x98, 0x37, 0xc0, + 0x81, 0x88, 0x58, 0x09, 0xde, 0xe0, 0xea, 0xf0, 0xc5, 0x44, 0x0e, 0x0f, 0x13, 0x13, 0x34, 0x30, + 0x21, 0x23, 0xdb, 0x8c, 0x63, 0x07, 0x4a, 0xcd, 0x88, 0xd6, 0xa9, 0x45, 0x9a, 0x04, 0x69, 0x60, + 0xec, 0xc0, 0x94, 0x41, 0x44, 0xaf, 0x03, 0x53, 0xf8, 0xdd, 0xd1, 0x10, 0xf5, 0xc0, 0xa9, 0x76, + 0x41, 0x0f, 0x24, 0xcd, 0xb1, 0xf3, 0xc0, 0x9e, 0x1c, 0x25, 0x88, 0xac, 0xac, 0x91, 0x41, 0x00, + 0xc8, 0x6f, 0x77, 0x48, 0x9e, 0x78, 0xc3, 0xaa, 0xdf, 0x03, 0x27, 0xa6, 0x40, 0x28, 0x2a, 0x13, + 0xe9, 0x08, 0xd9, 0x93, 0x41, 0xd0, 0xe6, 0xd8, 0x41, 0x42, 0x83, 0x15, 0x02, 0x0d, 0x34, 0xe0, + 0x8d, 0x34, 0x73, 0x6a, 0xc6, 0x7e, 0xc3, 0x3b, 0xff, 0x04, 0x3c, 0xb8, 0x3c, 0x5d, 0xdb, 0x03, + 0xb7, 0xc2, 0x7d, 0x91, 0x02, 0xa6, 0xe2, 0x13, 0xe0, 0xf9, 0x22, 0x3f, 0xe1, 0x9a, 0x22, 0xd3, + 0x09, 0xd0, 0x03, 0x18, 0x00, 0x01, 0x9b, 0x2e, 0x48, 0xec, 0x01, 0x34, 0x10, 0xc3, 0x04, 0xd3, + 0x69, 0xa4, 0xd3, 0x5e, 0x11, 0x39, 0x46, 0x96, 0x40, 0x53, 0x44, 0xa4, 0x02, 0x59, 0x1a, 0xe5, + 0x97, 0x95, 0x68, 0x17, 0xd1, 0x80, 0x92, 0x77, 0xfd, 0x69, 0x34, 0x81, 0x83, 0x6d, 0x25, 0xe4, + 0xe1, 0x87, 0x0e, 0x3c, 0x48, 0x90, 0x6a, 0x0c, 0x89, 0x48, 0x10, 0x77, 0x74, 0x85, 0x44, 0x10, + 0x6e, 0x11, 0x4e, 0xd4, 0x9f, 0x84, 0x2b, 0x10, 0x68, 0x97, 0x69, 0x10, 0x31, 0x27, 0xd0, 0x72, + 0x38, 0xe6, 0xa8, 0x63, 0x8e, 0x44, 0x4d, 0x74, 0xd4, 0x5d, 0x13, 0xa1, 0xe8, 0x13, 0x41, 0x31, + 0x60, 0xe4, 0x02, 0x7a, 0x22, 0xa9, 0xd5, 0xd1, 0x61, 0x35, 0x4e, 0x84, 0x80, 0x42, 0x0e, 0x5d, + 0x70, 0x83, 0x48, 0xac, 0xf5, 0xe8, 0xa3, 0x46, 0x2e, 0xac, 0x30, 0x9a, 0x48, 0x45, 0x66, 0xc4, + 0x80, 0x77, 0x01, 0x74, 0x69, 0x91, 0x75, 0x05, 0x0a, 0x80, 0xa4, 0x59, 0x5e, 0x92, 0x54, 0x92, + 0x94, 0x5f, 0x3d, 0xf9, 0x16, 0x09, 0x59, 0x6d, 0x44, 0x03, 0x98, 0x31, 0xfd, 0x48, 0x58, 0x56, + 0x20, 0x20, 0x45, 0x90, 0x71, 0xe2, 0xf5, 0x39, 0xde, 0x44, 0xe6, 0x05, 0xea, 0xdf, 0x4e, 0x1c, + 0x90, 0xe0, 0x40, 0x95, 0x7e, 0xf2, 0x45, 0x9e, 0xa0, 0xe6, 0x75, 0xc0, 0x80, 0x04, 0x00, 0x0a, + 0x85, 0x00, 0x82, 0x89, 0x86, 0xb7, 0x28, 0xa3, 0x82, 0x4e, 0x40, 0x27, 0x41, 0x94, 0x56, 0x2a, + 0xde, 0xa5, 0x98, 0x32, 0x5a, 0x58, 0x6a, 0x7d, 0xed, 0x90, 0x10, 0x93, 0x9e, 0x02, 0x00, 0x2a, + 0x47, 0x2e, 0x78, 0x14, 0x2a, 0x53, 0xb6, 0x75, 0xff, 0x0a, 0x91, 0x03, 0x53, 0xc6, 0x84, 0x00, + 0x09, 0x7c, 0x5d, 0x70, 0x82, 0x7b, 0x29, 0x21, 0x25, 0xc1, 0xa6, 0x03, 0x35, 0x90, 0x61, 0x46, + 0x2e, 0x48, 0x18, 0xec, 0xb0, 0x16, 0xb1, 0x45, 0x62, 0x44, 0x70, 0x92, 0xb5, 0x58, 0x49, 0x0a, + 0x0a, 0xb5, 0x91, 0xb1, 0x31, 0xa1, 0x79, 0x11, 0xb5, 0x03, 0x69, 0xc9, 0x51, 0x0c, 0x50, 0x3e, + 0x74, 0x01, 0xaf, 0x05, 0x9d, 0x80, 0xaa, 0x0a, 0x36, 0x0a, 0x24, 0x2b, 0x00, 0xdf, 0xa2, 0xb4, + 0x82, 0x04, 0x13, 0x4c, 0x00, 0x02, 0x80, 0x96, 0xa1, 0xb4, 0x5d, 0xbb, 0x20, 0xd0, 0xa9, 0xe4, + 0x98, 0x3e, 0xd2, 0x46, 0x43, 0x03, 0x76, 0x76, 0x24, 0x17, 0x41, 0xea, 0x31, 0x3b, 0x11, 0x9f, + 0xe8, 0xa2, 0xe4, 0xc2, 0x46, 0x2c, 0x0a, 0x30, 0xc2, 0x44, 0x06, 0x1c, 0xac, 0x21, 0xc3, 0xd7, + 0x4e, 0x24, 0xe6, 0x8c, 0x02, 0x2f, 0xe8, 0x64, 0x43, 0xcd, 0x36, 0x67, 0xd7, 0x44, 0xda, 0x72, + 0x64, 0x21, 0x41, 0x68, 0xea, 0x96, 0xd2, 0x76, 0x74, 0xd1, 0xf8, 0x50, 0xb9, 0x16, 0xff, 0xc4, + 0x50, 0xb9, 0xfd, 0x32, 0xe5, 0x42, 0x90, 0x74, 0x5d, 0x69, 0xd1, 0xc2, 0x3b, 0x21, 0x6b, 0x91, + 0xc9, 0x0e, 0x65, 0x2c, 0x10, 0xaa, 0xe2, 0x4d, 0xc1, 0x71, 0x60, 0x32, 0xb3, 0xea, 0x59, 0x46, + 0x20, 0x6d, 0x6a, 0xb3, 0x00, 0x38, 0x37, 0xb4, 0x83, 0x48, 0xdd, 0x46, 0x09, 0x62, 0x42, 0x4a, + 0x8b, 0xd4, 0x31, 0xb1, 0x18, 0x89, 0x1c, 0x2c, 0x47, 0xbe, 0x01, 0x7a, 0xde, 0xd0, 0x18, 0x31, + 0xd0, 0x74, 0x43, 0x0e, 0xa0, 0x34, 0x85, 0x0a, 0x87, 0x39, 0x40, 0x02, 0xb8, 0x02, 0xe1, 0xea, + 0x50, 0xd8, 0x49, 0x4a, 0x00, 0x1b, 0x0d, 0x9d, 0x71, 0x96, 0xe4, 0x04, 0x53, 0x75, 0x00, 0x37, + 0x4a, 0x05, 0x42, 0xa5, 0x9f, 0xdb, 0x15, 0x8d, 0x61, 0x2a, 0xd0, 0xd1, 0x0c, 0x2c, 0x0b, 0x51, + 0xad, 0x6d, 0xf2, 0xec, 0xd0, 0x70, 0x35, 0x61, 0x69, 0x71, 0xcb, 0x7a, 0x0b, 0x65, 0x2d, 0x46, + 0x21, 0x11, 0x0c, 0x91, 0xce, 0x29, 0x41, 0x80, 0x68, 0x4b, 0x0e, 0xa0, 0xac, 0x35, 0x96, 0xd8, + 0x96, 0xd5, 0x51, 0xe7, 0x8f, 0x63, 0x44, 0x73, 0x00, 0x6e, 0xc5, 0xa5, 0x02, 0x09, 0xa8, 0x93, + 0xf0, 0xc2, 0xe5, 0x7e, 0xae, 0x1a, 0xd6, 0x08, 0x12, 0xc4, 0x2e, 0x01, 0x85, 0xaf, 0x66, 0x64, + 0x75, 0x41, 0x5f, 0xa7, 0xaa, 0xe8, 0xe6, 0xb5, 0x0b, 0x3a, 0x3a, 0x4a, 0x37, 0xe4, 0xae, 0xfb, + 0xbf, 0x1a, 0xf7, 0x3e, 0x18, 0x0d, 0x91, 0x0e, 0x14, 0x10, 0x00, 0x3b +}; + +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 ); + +/*------------------------------------------------------------------ */ +/* end of monitor.c */
