/* ================================================================= * * monitor.c * * An HTTP system monitor * * ================================================================= * ####ECOSGPLCOPYRIGHTBEGIN#### * ------------------------------------------- * This file is part of eCos, the Embedded Configurable Operating System. * Copyright (C) 2002, 2003 Free Software Foundation, Inc. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 v2. * * 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, andrew.lunn@ascom.ch * Date: 2002-10-14 * Purpose: * Description: * * ####DESCRIPTIONEND#### * * ================================================================= */ #include #include #include #include #include #include /* tracing macros */ #include /* assertion macros */ #include #include #ifdef CYGPKG_KERNEL_INSTRUMENT #include #include #endif #include #include /* ================================================================= */ /* Include all the necessary network headers by hand. We need to do * this so that _KERNEL is correctly defined, or not, for specific * headers so we can use both the external API and get at internal * kernel structures. */ #define _KERNEL #include #undef _KERNEL #include #include #include #include #include #define _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CYGPKG_NET_INET6 #include #include #include #include #include #endif #include #include /* ================================================================= */ /* Use this when a thread appears to have no name. */ #define NULL_THREAD_NAME "----------" /* ================================================================= */ /* Draw navigation bar * * This draws a simple table containing links to the various monitor * pages at the current position in the HTML stream. */ static void draw_navbar( FILE *client ) { html_para_begin( client, "" ); html_table_begin( client, "border cellpadding=\"4\"" ); { html_table_row_begin(client, "" ); { html_table_data_begin( client, "" ); html_image( client, "/monitor/ecos.gif", "eCos logo", "" ); html_table_data_begin( client, "" ); html_url( client, "Threads", "/monitor/threads.html"); html_table_data_begin( client, "" ); html_url( client, "Interrupts", "/monitor/interrupts.html"); html_table_data_begin( client, "" ); html_url( client, "Memory", "/monitor/memory.html"); html_table_data_begin( client, "" ); html_url( client, "Network", "/monitor/network.html"); #ifdef CYGPKG_KERNEL_INSTRUMENT html_table_data_begin( client, "" ); html_url( client, "Instrumentation", "/monitor/instrument.html"); #endif } html_table_row_end( client ); } html_table_end( client ); } /* ================================================================= */ /* Index page * * A simple introductory page matching "/monitor" and * "/monitor/index.html". */ static char monitor_index_blurb[] = "

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

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

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

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

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

Once the new state has been selected, press the Submit " "button to make the change, or Reset to clear it." ; static cyg_bool cyg_monitor_thread_edit( FILE * client, char *filename, char *formdata, void *arg ) { /* If any form data has been supplied, then change the thread's * state accordingly. */ if( formdata != NULL ) { char *formlist[6]; char *state; char *pri_string; char *id_string; cyg_handle_t thread = 0; cyg_uint16 id; /* Parse the data */ cyg_formdata_parse( formdata, formlist, 6 ); /* Get the thread id from the hidden control */ id_string = cyg_formlist_find( formlist, "thread"); sscanf( id_string, "%04hx", &id ); thread = cyg_thread_find( id ); /* If there is a pri field, change the priority */ pri_string = cyg_formlist_find( formlist, "pri"); if( pri_string != NULL ) { cyg_priority_t pri; sscanf( pri_string, "%d", &pri ); cyg_thread_set_priority( thread, pri ); } /* If there is a state field, change the thread state */ state = cyg_formlist_find( formlist, "state"); if( state != NULL ) { if( strcmp( state, "run" ) == 0 ) cyg_thread_resume( thread ); if( strcmp( state, "suspend" ) == 0 ) cyg_thread_suspend( thread ); if( strcmp( state, "release" ) == 0 ) cyg_thread_release( thread ); } } /* Now generate a page showing the current thread state, and * including form controls to change it. */ html_begin(client); html_head(client,"eCos Thread Editor", ""); html_body_begin(client,""); { cyg_uint16 id; cyg_thread_info info; cyg_handle_t thread = 0; char idbuf[16]; sscanf( filename, "/monitor/thread-%04hx.html", &id ); thread = cyg_thread_find( id ); cyg_thread_get_info(thread, id, &info ); html_heading(client, 2, "Thread State Editor" ); html_para_begin( client, "" ); fprintf( client, "Editing Thread %04x %s\n",id, info.name?info.name:NULL_THREAD_NAME); fputs( thread_edit_blurb, client ); html_form_begin( client, filename, "" ); { html_table_begin( client, "border" ); { html_table_header( client, "Property", "" ); html_table_header( client, "Value", "" ); html_table_row_begin(client, "" ); { html_table_data_begin( client, "" ); fputs( "State", client ); html_table_data_begin( client, "" ); html_form_input_radio( client, "state", "run", (info.state&0x04)==0 ); fputs( "Run", client ); html_form_input_radio( client, "state", "suspend", (info.state&0x04)!=0 ); fputs( "Suspend", client ); html_form_input_radio( client, "state", "release", 0 ); fputs( "Release", client ); } html_table_row_end( client ); html_table_row_begin(client, "" ); { html_table_data_begin( client, "" ); fputs( "Priority", client ); html_table_data_begin( client, "" ); fprintf(client,"\n", info.set_pri); } html_table_row_end( client ); } html_table_end( client ); /* Add submit and reset buttons */ html_form_input(client, "submit", "submit", "Submit", ""); html_form_input(client, "reset", "reset", "Reset", ""); /* Pass the thread ID through to our next incarnation */ sprintf( idbuf, "%04x", id ); html_form_input_hidden(client, "thread", idbuf ); } html_form_end( client ); draw_navbar(client); } html_body_end(client); html_end(client); return 1; } CYG_HTTPD_TABLE_ENTRY( cyg_monitor_thread_edit_entry, "/monitor/thread-*", cyg_monitor_thread_edit, NULL ); /* ================================================================= */ /* Interrupt monitor * * At present this just generates a table showing which interrupts * have an ISR attached. */ static cyg_bool cyg_monitor_interrupts( FILE * client, char *filename, char *formdata, void *arg ) { html_begin(client); html_head(client,"eCos Interrupt Monitor", ""); html_body_begin(client,""); { html_heading(client, 2, "Interrupt Monitor" ); html_table_begin( client, "border" ); { int i; int maxint = CYGNUM_HAL_ISR_MAX; #ifdef CYGPKG_HAL_I386 maxint = CYGNUM_HAL_ISR_MIN+16; #endif html_table_header( client, "ISR", "" ); html_table_header( client, "State", "" ); for( i = CYGNUM_HAL_ISR_MIN; i <= maxint ; i++ ) { cyg_bool_t inuse; HAL_INTERRUPT_IN_USE( i, inuse ); html_table_row_begin(client, "" ); { html_table_data_begin( client, "" ); fprintf( client, "%d", i); html_table_data_begin( client, "" ); fprintf( client, "%s", inuse?"In Use":"Free"); } html_table_row_end( client ); } } html_table_end( client ); draw_navbar(client); } html_body_end(client); html_end(client); return 1; } CYG_HTTPD_TABLE_ENTRY( cyg_monitor_interrupts_entry, "/monitor/interrupts.htm*", cyg_monitor_interrupts, NULL ); /* ================================================================= */ /* Memory monitor * * Generates a table showing a 256 byte page of memory. Form controls * allow changes to the base address and display element size. */ static cyg_bool cyg_monitor_memory( FILE * client, char *filename, char *formdata, void *arg ) { char *formlist[10]; cyg_uint32 base = 0; unsigned int datasize = 1; int size = 256; char *p; bool valid_base = true; cyg_formdata_parse( formdata, formlist, 10 ); p = cyg_formlist_find( formlist, "base" ); /* If the page is requested without a 'base' parameter, do not attempt * to access any memory locations to prevent illegal memory accesses * on targets where '0' is not a valid address. */ if( p != NULL ) sscanf( p, "%x", &base ); else valid_base = false; p = cyg_formlist_find( formlist, "datasize" ); if( p != NULL ) sscanf( p, "%x", &datasize ); if( cyg_formlist_find( formlist, "next" ) != NULL ) base += size; if( cyg_formlist_find( formlist, "prev" ) != NULL ) base -= size; html_begin(client); html_head(client,"eCos Memory Monitor", ""); html_body_begin(client,""); { html_heading(client, 2, "Memory Monitor" ); html_form_begin( client, "/monitor/memory.html", "" ); { /* Text input control for base address */ html_para_begin( client, "" ); fprintf(client, "Base Address: 0x\n", base); fprintf(client, "WARNING: entering an illegal base address can crash the system.\n"); /* 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, "" ); if (valid_base == true) { 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 ifaddrs *iflist, *ifp; if(getifaddrs(&iflist)!=0) return 0; 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" ); { char addr[64]; int i; ifp = iflist; html_table_header( client, "Interface", "" ); html_table_header( client, "Status", "" ); while( ifp != (struct ifaddrs *)NULL) { if (ifp->ifa_addr->sa_family != AF_LINK) { html_table_row_begin(client, "" ); { html_table_data_begin( client, "" ); fprintf( client, "%s", ifp->ifa_name); html_table_data_begin( client, "" ); html_table_begin( client, "" ); { /* Get the interface's flags and display * the interesting ones. */ html_table_row_begin(client, "" ); fprintf( client, "Flags\n" ); for( i = 0; i < 16; i++ ) { switch( ifp->ifa_flags & (1<ifa_addr, sizeof(*ifp->ifa_addr), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); fprintf( client, "Address%s\n", addr); html_table_row_end( client ); if (ifp->ifa_netmask) { html_table_row_begin(client, "" ); getnameinfo(ifp->ifa_netmask, sizeof(*ifp->ifa_netmask), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); fprintf( client, "Mask%s\n", addr); html_table_row_end( client ); } if (ifp->ifa_broadaddr) { html_table_row_begin(client, "" ); getnameinfo(ifp->ifa_broadaddr, sizeof(*ifp->ifa_broadaddr), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST); fprintf( client, "Broadcast%s\n", addr); html_table_row_end( client ); } } html_table_end( client ); } html_table_row_end( client ); } ifp = ifp->ifa_next; } } 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, "IPv4", "" ); #ifdef CYGPKG_NET_INET6 html_table_header( client, "IPv6", "" ); #endif html_table_header( client, "ICMPv4", "" ); #ifdef CYGPKG_NET_INET6 html_table_header( client, "ICMPv6", "" ); #endif html_table_header( client, "UDP", "" ); html_table_header( client, "TCP", "" ); html_table_row_begin(client, "" ); { html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%ld\n", "Total", ipstat.ips_total ); fprintf( client, "%s%ld\n", "Bad", ipstat.ips_badsum+ ipstat.ips_tooshort+ ipstat.ips_toosmall+ ipstat.ips_badhlen+ ipstat.ips_badlen+ ipstat.ips_noproto+ ipstat.ips_toolong ); fprintf( client, "%s%ld\n", "Reassembled", ipstat.ips_reassembled ); fprintf( client, "%s%ld\n", "Delivered", ipstat.ips_delivered ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%ld\n", "Total", ipstat.ips_localout ); fprintf( client, "%s%ld\n", "Raw", ipstat.ips_rawout ); fprintf( client, "%s%ld\n", "Fragmented", ipstat.ips_fragmented ); } html_table_end( client ); #ifdef CYGPKG_NET_INET6 html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%lld\n", "Total", ip6stat.ip6s_total ); fprintf( client, "%s%lld\n", "Bad", ip6stat.ip6s_tooshort+ ip6stat.ip6s_toosmall ); fprintf( client, "%s%lld\n", "Reassembled", ip6stat.ip6s_reassembled ); fprintf( client, "%s%lld\n", "Delivered", ip6stat.ip6s_delivered ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%lld\n", "Total", ip6stat.ip6s_localout ); fprintf( client, "%s%lld\n", "Raw", ip6stat.ip6s_rawout ); fprintf( client, "%s%lld\n", "Fragmented", ip6stat.ip6s_fragmented ); } html_table_end( client ); #endif html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%ld\n", "ECHO", icmpstat.icps_inhist[ICMP_ECHO] ); fprintf( client, "%s%ld\n", "ECHO REPLY", icmpstat.icps_inhist[ICMP_ECHOREPLY] ); fprintf( client, "%s%ld\n", "UNREACH", icmpstat.icps_inhist[ICMP_UNREACH] ); fprintf( client, "%s%ld\n", "REDIRECT", icmpstat.icps_inhist[ICMP_REDIRECT] ); fprintf( client, "%s%ld\n", "Other", icmpstat.icps_inhist[ICMP_SOURCEQUENCH]+ icmpstat.icps_inhist[ICMP_ROUTERADVERT]+ icmpstat.icps_inhist[ICMP_ROUTERSOLICIT]+ icmpstat.icps_inhist[ICMP_TIMXCEED]+ icmpstat.icps_inhist[ICMP_PARAMPROB]+ icmpstat.icps_inhist[ICMP_TSTAMP]+ icmpstat.icps_inhist[ICMP_TSTAMPREPLY]+ icmpstat.icps_inhist[ICMP_IREQ]+ icmpstat.icps_inhist[ICMP_IREQREPLY]+ icmpstat.icps_inhist[ICMP_MASKREQ]+ icmpstat.icps_inhist[ICMP_MASKREPLY] ); fprintf( client, "%s%ld\n", "Bad", icmpstat.icps_badcode+ icmpstat.icps_tooshort+ icmpstat.icps_checksum+ icmpstat.icps_badlen+ icmpstat.icps_bmcastecho ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%ld\n", "ECHO", icmpstat.icps_outhist[ICMP_ECHO] ); fprintf( client, "%s%ld\n", "ECHO REPLY", icmpstat.icps_outhist[ICMP_ECHOREPLY] ); fprintf( client, "%s%ld\n", "UNREACH", icmpstat.icps_outhist[ICMP_UNREACH] ); fprintf( client, "%s%ld\n", "REDIRECT", icmpstat.icps_outhist[ICMP_REDIRECT] ); fprintf( client, "%s%ld\n", "Other", icmpstat.icps_inhist[ICMP_SOURCEQUENCH]+ icmpstat.icps_outhist[ICMP_ROUTERADVERT]+ icmpstat.icps_outhist[ICMP_ROUTERSOLICIT]+ icmpstat.icps_outhist[ICMP_TIMXCEED]+ icmpstat.icps_outhist[ICMP_PARAMPROB]+ icmpstat.icps_outhist[ICMP_TSTAMP]+ icmpstat.icps_outhist[ICMP_TSTAMPREPLY]+ icmpstat.icps_outhist[ICMP_IREQ]+ icmpstat.icps_outhist[ICMP_IREQREPLY]+ icmpstat.icps_outhist[ICMP_MASKREQ]+ icmpstat.icps_outhist[ICMP_MASKREPLY] ); } html_table_end( client ); #ifdef CYGPKG_NET_INET6 html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%lld\n", "ECHO", icmp6stat.icp6s_inhist[ICMP_ECHO] ); fprintf( client, "%s%lld\n", "ECHO REPLY", icmp6stat.icp6s_inhist[ICMP_ECHOREPLY] ); fprintf( client, "%s%lld\n", "UNREACH", icmp6stat.icp6s_inhist[ICMP_UNREACH] ); fprintf( client, "%s%lld\n", "REDIRECT", icmp6stat.icp6s_inhist[ICMP_REDIRECT] ); fprintf( client, "%s%lld\n", "Other", icmp6stat.icp6s_inhist[ICMP_SOURCEQUENCH]+ icmp6stat.icp6s_inhist[ICMP_ROUTERADVERT]+ icmp6stat.icp6s_inhist[ICMP_ROUTERSOLICIT]+ icmp6stat.icp6s_inhist[ICMP_TIMXCEED]+ icmp6stat.icp6s_inhist[ICMP_PARAMPROB]+ icmp6stat.icp6s_inhist[ICMP_TSTAMP]+ icmp6stat.icp6s_inhist[ICMP_TSTAMPREPLY]+ icmp6stat.icp6s_inhist[ICMP_IREQ]+ icmp6stat.icp6s_inhist[ICMP_IREQREPLY]+ icmp6stat.icp6s_inhist[ICMP_MASKREQ]+ icmp6stat.icp6s_inhist[ICMP_MASKREPLY] ); fprintf( client, "%s%lld\n", "Bad", icmp6stat.icp6s_badcode+ icmp6stat.icp6s_tooshort+ icmp6stat.icp6s_checksum+ icmp6stat.icp6s_badlen ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%lld\n", "ECHO", icmp6stat.icp6s_outhist[ICMP_ECHO] ); fprintf( client, "%s%lld\n", "ECHO REPLY", icmp6stat.icp6s_outhist[ICMP_ECHOREPLY] ); fprintf( client, "%s%lld\n", "UNREACH", icmp6stat.icp6s_outhist[ICMP_UNREACH] ); fprintf( client, "%s%lld\n", "REDIRECT", icmp6stat.icp6s_outhist[ICMP_REDIRECT] ); fprintf( client, "%s%lld\n", "Other", icmp6stat.icp6s_inhist[ICMP_SOURCEQUENCH]+ icmp6stat.icp6s_outhist[ICMP_ROUTERADVERT]+ icmp6stat.icp6s_outhist[ICMP_ROUTERSOLICIT]+ icmp6stat.icp6s_outhist[ICMP_TIMXCEED]+ icmp6stat.icp6s_outhist[ICMP_PARAMPROB]+ icmp6stat.icp6s_outhist[ICMP_TSTAMP]+ icmp6stat.icp6s_outhist[ICMP_TSTAMPREPLY]+ icmp6stat.icp6s_outhist[ICMP_IREQ]+ icmp6stat.icp6s_outhist[ICMP_IREQREPLY]+ icmp6stat.icp6s_outhist[ICMP_MASKREQ]+ icmp6stat.icp6s_outhist[ICMP_MASKREPLY] ); } html_table_end( client ); #endif html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%ld\n", "Total", udpstat.udps_ipackets ); fprintf( client, "%s%ld\n", "Bad", udpstat.udps_hdrops+ udpstat.udps_badsum+ udpstat.udps_badlen+ udpstat.udps_noport+ udpstat.udps_noportbcast+ udpstat.udps_fullsock ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%ld\n", "Total", udpstat.udps_opackets ); } html_table_end( client ); html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s:\n", "Connections" ); fprintf( client, "%s%ld\n", "Initiated", tcpstat.tcps_connattempt ); fprintf( client, "%s%ld\n", "Accepted", tcpstat.tcps_accepts ); fprintf( client, "%s%ld\n", "Established", tcpstat.tcps_connects ); fprintf( client, "%s%ld\n", "Closed", tcpstat.tcps_closed ); fprintf( client, "%s:\n", "Received" ); fprintf( client, "%s%ld\n", "Packets", tcpstat.tcps_rcvtotal ); fprintf( client, "%s%ld\n", "Data Packets", tcpstat.tcps_rcvpack ); fprintf( client, "%s%ld\n", "Bytes", tcpstat.tcps_rcvbyte ); fprintf( client, "%s:\n", "Sent" ); fprintf( client, "%s%ld\n", "Packets", tcpstat.tcps_sndtotal ); fprintf( client, "%s%ld\n", "Data Packets", tcpstat.tcps_sndpack ); fprintf( client, "%s%ld\n", "Bytes", tcpstat.tcps_sndbyte ); } html_table_end( client ); } html_table_row_end( client ); } html_table_end( client ); html_para_begin( client, "" ); html_heading(client, 3, "Mbufs" ); html_table_begin( client, "border" ); { html_table_header( client, "Summary", "" ); html_table_header( client, "Types", "" ); html_table_row_begin( client, "" ); { html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { fprintf( client, "%s%ld\n", "Mbufs", mbstat.m_mbufs ); fprintf( client, "%s%ld\n", "Clusters", mbstat.m_clusters ); fprintf( client, "%s%ld\n", "Free Clusters", mbstat.m_clfree ); fprintf( client, "%s%ld\n", "Drops", mbstat.m_drops ); fprintf( client, "%s%ld\n", "Waits", mbstat.m_wait ); fprintf( client, "%s%ld\n", "Drains", mbstat.m_drain ); #if defined(CYGPKG_NET_FREEBSD_STACK) fprintf( client, "%s%ld\n", "Copy Fails", mbstat.m_mcfail ); fprintf( client, "%s%ld\n", "Pullup Fails", mbstat.m_mpfail ); #endif } html_table_end( client ); html_table_data_begin( client, "valign=\"top\"" ); html_table_begin( client, "" ); { u_long *mtypes; #if defined(CYGPKG_NET_FREEBSD_STACK) mtypes = mbtypes; #else mtypes = mbstat.m_mtypes; #endif fprintf( client, "%s%ld\n", "FREE", mtypes[MT_FREE] ); fprintf( client, "%s%ld\n", "DATA", mtypes[MT_DATA] ); fprintf( client, "%s%ld\n", "HEADER", mtypes[MT_HEADER] ); #if !defined(CYGPKG_NET_FREEBSD_STACK) fprintf( client, "%s%ld\n", "SOCKET", mtypes[MT_SOCKET] ); fprintf( client, "%s%ld\n", "PCB", mtypes[MT_PCB] ); fprintf( client, "%s%ld\n", "RTABLE", mtypes[MT_RTABLE] ); fprintf( client, "%s%ld\n", "HTABLE", mtypes[MT_HTABLE] ); fprintf( client, "%s%ld\n", "ATABLE", mtypes[MT_ATABLE] ); #endif fprintf( client, "%s%ld\n", "SONAME", mtypes[MT_SONAME] ); #if !defined(CYGPKG_NET_FREEBSD_STACK) fprintf( client, "%s%ld\n", "SOOPTS", mtypes[MT_SOOPTS] ); #endif fprintf( client, "%s%ld\n", "FTABLE", mtypes[MT_FTABLE] ); /* Ignore the rest for now... */ } html_table_end( client ); } html_table_row_end( client ); } html_table_end( client ); draw_navbar(client); } html_body_end(client); html_end(client); freeifaddrs(iflist); return 1; } CYG_HTTPD_TABLE_ENTRY( cyg_monitor_network_entry, "/monitor/network.htm*", cyg_monitor_network, NULL ); /* ================================================================= */ /* Instrumentation Monitor * * If the CYGPKG_KERNEL_INSTRUMENT option is set, we generate a table * showing the current instrumentation buffer. If the FLAGS option is * enabled we also print a table giving control of the flags. * */ #ifdef CYGPKG_KERNEL_INSTRUMENT /* Instrumentation record. */ struct Instrument_Record { CYG_WORD16 type; // record type CYG_WORD16 thread; // current thread id CYG_WORD timestamp; // 32 bit timestamp CYG_WORD arg1; // first arg CYG_WORD arg2; // second arg }; typedef struct Instrument_Record Instrument_Record; /* Instrumentation variables, these live in the * instrumentation files in the kernel */ __externC Instrument_Record *instrument_buffer_pointer; __externC Instrument_Record instrument_buffer[]; __externC cyg_uint32 instrument_buffer_size; #if defined(CYGDBG_KERNEL_INSTRUMENT_FLAGS) && \ defined(CYGDBG_KERNEL_INSTRUMENT_MSGS) static cyg_uint32 instrument_flags[(CYG_INSTRUMENT_CLASS_MAX>>8)+1]; #endif static char cyg_monitor_instrument_blurb1[] = "

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