Initial revision
authorlothar <lothar>
Fri, 13 Feb 2009 16:55:51 +0000 (16:55 +0000)
committerlothar <lothar>
Fri, 13 Feb 2009 16:55:51 +0000 (16:55 +0000)
75 files changed:
packages/compat/posix/v2_0/include/sys/time.h [new file with mode: 0644]
packages/compat/posix/v2_0/tests/pmqueue1.c [new file with mode: 0644]
packages/compat/posix/v2_0/tests/pmqueue2.c [new file with mode: 0644]
packages/compat/posix/v2_0/tests/pmutex3.c [new file with mode: 0644]
packages/compat/posix/v2_0/tests/tm_posix.cxx [new file with mode: 0644]
packages/net/.cvsignore [new file with mode: 0644]
packages/net/athttpd/v2_0/ChangeLog [new file with mode: 0644]
packages/net/athttpd/v2_0/cdl/httpd.cdl [new file with mode: 0644]
packages/net/athttpd/v2_0/doc/athttpd.sgml [new file with mode: 0644]
packages/net/athttpd/v2_0/doc/mime_types.txt [new file with mode: 0644]
packages/net/athttpd/v2_0/include/auth.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/cgi.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/digcalc.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/forms.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/global.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/handler.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/http.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/jim.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/md5.h [new file with mode: 0644]
packages/net/athttpd/v2_0/include/socket.h [new file with mode: 0644]
packages/net/athttpd/v2_0/src/auth.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/cgi.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/forms.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/handler.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/http.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/jim-aio.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/jim.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/md5c.c [new file with mode: 0644]
packages/net/athttpd/v2_0/src/socket.c [new file with mode: 0644]
packages/net/autotest/v2_0/ChangeLog [new file with mode: 0644]
packages/net/autotest/v2_0/cdl/net_autotest.cdl [new file with mode: 0644]
packages/net/autotest/v2_0/doc/host.txt [new file with mode: 0644]
packages/net/autotest/v2_0/doc/strategy.txt [new file with mode: 0644]
packages/net/autotest/v2_0/host/_suping.c [new file with mode: 0644]
packages/net/autotest/v2_0/host/awaitorder.c [new file with mode: 0644]
packages/net/autotest/v2_0/host/floodping.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/makefile [new file with mode: 0644]
packages/net/autotest/v2_0/host/obey.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/sendack.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/slowping.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/snmpwalk.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/tftpget.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/tftpput.sh [new file with mode: 0755]
packages/net/autotest/v2_0/host/tmpfile.c [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_bootp.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_corrupt.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_failrx.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_failtx.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_rt.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_snmp.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/permtests/netauto_std.ptest [new file with mode: 0644]
packages/net/autotest/v2_0/tests/autohost.inl [new file with mode: 0644]
packages/net/autotest/v2_0/tests/floodping.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/floodpingmux.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/memcheck.inl [new file with mode: 0644]
packages/net/autotest/v2_0/tests/route_3.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/route_3_4.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/route_4.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/route_none.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/routeping.inl [new file with mode: 0644]
packages/net/autotest/v2_0/tests/slowping.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/slowpingmux.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/snmpmulti.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/snmppings.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/snmpwalk.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv.inl [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_g0.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_g1M.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_g512.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_get.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_p0.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_p1M.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_p512.c [new file with mode: 0644]
packages/net/autotest/v2_0/tests/tftp_serv_put.c [new file with mode: 0644]
packages/net/ipsec/.cvsignore [new file with mode: 0644]

diff --git a/packages/compat/posix/v2_0/include/sys/time.h b/packages/compat/posix/v2_0/include/sys/time.h
new file mode 100644 (file)
index 0000000..c695862
--- /dev/null
@@ -0,0 +1,173 @@
+//==========================================================================
+//
+//      include/sys/time.h
+//
+//      
+//
+//==========================================================================
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD or other sources,
+// and are covered by the appropriate copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2000-01-10
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+/*     $OpenBSD: time.h,v 1.9 1999/12/06 19:36:42 aaron Exp $  */
+/*     $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $        */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)time.h      8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+       long    tv_sec;         /* seconds */
+       long    tv_usec;        /* and microseconds */
+};
+
+
+#define        TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
+       (ts)->tv_sec = (tv)->tv_sec;                                    \
+       (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
+}
+#define        TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
+       (tv)->tv_sec = (ts)->tv_sec;                                    \
+       (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
+}
+
+struct timezone {
+       int     tz_minuteswest; /* minutes west of Greenwich */
+       int     tz_dsttime;     /* type of dst correction */
+};
+
+#define        DST_NONE        0       /* not on dst */
+#define        DST_USA         1       /* USA style dst */
+#define        DST_AUST        2       /* Australian style dst */
+#define        DST_WET         3       /* Western European dst */
+#define        DST_MET         4       /* Middle European dst */
+#define        DST_EET         5       /* Eastern European dst */
+#define        DST_CAN         6       /* Canada */
+
+/* Operations on timevals. */
+#define        timerclear(tvp)         (tvp)->tv_sec = (tvp)->tv_usec = 0
+#define        timerisset(tvp)         ((tvp)->tv_sec || (tvp)->tv_usec)
+#define        timercmp(tvp, uvp, cmp)                                         \
+       (((tvp)->tv_sec == (uvp)->tv_sec) ?                             \
+           ((tvp)->tv_usec cmp (uvp)->tv_usec) :                       \
+           ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define        timeradd(tvp, uvp, vvp)                                         \
+       do {                                                            \
+               (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
+               (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
+               if ((vvp)->tv_usec >= 1000000) {                        \
+                       (vvp)->tv_sec++;                                \
+                       (vvp)->tv_usec -= 1000000;                      \
+               }                                                       \
+       } while (0)
+#define        timersub(tvp, uvp, vvp)                                         \
+       do {                                                            \
+               (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;          \
+               (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;       \
+               if ((vvp)->tv_usec < 0) {                               \
+                       (vvp)->tv_sec--;                                \
+                       (vvp)->tv_usec += 1000000;                      \
+               }                                                       \
+       } while (0)
+
+/* Operations on timespecs. */
+#define        timespecclear(tsp)              (tsp)->tv_sec = (tsp)->tv_nsec = 0
+#define        timespecisset(tsp)              ((tsp)->tv_sec || (tsp)->tv_nsec)
+#define        timespeccmp(tsp, usp, cmp)                                      \
+       (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
+           ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
+           ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define        timespecadd(tsp, usp, vsp)                                      \
+       do {                                                            \
+               (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;          \
+               (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;       \
+               if ((vsp)->tv_nsec >= 1000000000L) {                    \
+                       (vsp)->tv_sec++;                                \
+                       (vsp)->tv_nsec -= 1000000000L;                  \
+               }                                                       \
+       } while (0)
+#define        timespecsub(tsp, usp, vsp)                                      \
+       do {                                                            \
+               (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;          \
+               (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;       \
+               if ((vsp)->tv_nsec < 0) {                               \
+                       (vsp)->tv_sec--;                                \
+                       (vsp)->tv_nsec += 1000000000L;                  \
+               }                                                       \
+       } while (0)
+
+
+int    gettimeofday(struct timeval *, struct timezone *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/packages/compat/posix/v2_0/tests/pmqueue1.c b/packages/compat/posix/v2_0/tests/pmqueue1.c
new file mode 100644 (file)
index 0000000..38272a0
--- /dev/null
@@ -0,0 +1,359 @@
+/*========================================================================
+//
+//      pmqueue1.c
+//
+//      POSIX Message queues tests
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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.,
+// 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.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     jlarmour
+// Contributors:  
+// Date:          2000-05-18
+// Purpose:       This file provides tests for POSIX mqueues
+// Description:   
+// Usage:         
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/* CONFIGURATION */
+
+#include <pkgconf/posix.h>
+
+#ifndef CYGPKG_POSIX_MQUEUES
+# define NA_MSG "Message queues not configured"
+#endif
+
+#ifdef NA_MSG
+#include <cyg/infra/testcase.h>      // test API
+void
+cyg_user_start(void)
+{
+    CYG_TEST_NA( NA_MSG );
+}
+
+#else
+
+/* INCLUDES */
+
+#include <fcntl.h>                   // O_*
+#include <errno.h>                   // errno
+#include <sys/stat.h>                // file modes
+#include <mqueue.h>                  // Mqueue Header
+#include <cyg/infra/testcase.h>      // test API
+
+/* FUNCTIONS */
+
+static int
+my_memcmp(const void *m1, const void *m2, size_t n)
+{
+    char *s1 = (char *)m1;
+    char *s2 = (char *)m2;
+
+    while (n--) {
+        if (*s1 != *s2)
+            return *s1 - *s2;
+        s1++;
+        s2++;
+    }
+    return 0;
+} // my_memcmp()
+
+//************************************************************************
+
+int
+main(void)
+{
+    mqd_t q1, q2;
+    char buf[20];
+    ssize_t recvlen;
+    unsigned int prio;
+    struct mq_attr attr, oattr;
+    mode_t mode;
+    int err;
+
+    CYG_TEST_INIT();
+    CYG_TEST_INFO( "Starting POSIX message test 1" );
+
+    q1 = mq_open( "/mq1", O_RDWR );
+    CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" );
+    CYG_TEST_PASS_FAIL( ENOENT == errno,
+                        "errno correct for non-existent queue" );
+
+    attr.mq_flags = 0;
+    attr.mq_maxmsg = 4;
+    attr.mq_msgsize = 20;
+    mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all
+
+    q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_WRONLY, mode, &attr );
+    CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" );
+    
+    err = mq_getattr( q1, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (0 == attr.mq_curmsgs ), "getattr attributes correct" );
+                        
+    err = mq_send( q1, "Vik is brill", sizeof("Vik is brill"), 10 );
+
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_send" );
+    
+    err = mq_getattr( q1, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (1 == attr.mq_curmsgs ),
+                        "getattr attributes correct #2" );
+                        
+    q2 = mq_open( "/mq1", O_RDONLY|O_CREAT|O_EXCL );
+    CYG_TEST_PASS_FAIL( q2 == (mqd_t)-1,
+                        "error for exclusive open of existing queue" );
+    CYG_TEST_PASS_FAIL( EEXIST == errno,
+                        "errno correct for exclusive open of existing queue" );
+    
+    q2 = mq_open( "/mq1", O_RDONLY );
+    CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "simple mq_open (read only)" );
+    
+    err = mq_getattr( q2, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (1 == attr.mq_curmsgs ),
+                        "getattr attributes correct #3" );
+
+    err = mq_close( q2 );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_close" );
+    
+    q2 = mq_open( "/mq1", O_RDONLY );
+    CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "mq_open reopen (read only)" );
+    
+    err = mq_getattr( q2, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (1 == attr.mq_curmsgs ),
+                        "getattr attributes correct #4" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is brill"),
+                        "receive message length" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is brill",
+                                        sizeof("Vik is brill")),
+                        "received message data intact" );
+    CYG_TEST_PASS_FAIL( 10 == prio, "received at correct priority" );
+
+    err = mq_getattr( q1, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY != (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY == (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (0 == attr.mq_curmsgs ),
+                        "getattr attributes correct #5" );
+
+    attr.mq_flags |= O_NONBLOCK;
+    err = mq_setattr( q2, &attr, &oattr );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_setattr O_NONBLOCK" );
+    CYG_TEST_PASS_FAIL( (4 == oattr.mq_maxmsg) &&
+                        (20 == oattr.mq_msgsize) &&
+                        (O_NONBLOCK != (oattr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY == (oattr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY != (oattr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (oattr.mq_flags & O_RDWR)) &&
+                        (0 == oattr.mq_curmsgs ),
+                        "old attribute correct" );
+    err = mq_getattr( q2, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after O_NONBLOCK" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (0 == attr.mq_curmsgs ),
+                        "new attribute correct" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
+                        "mq_receive, empty buffer, non-blocking" );
+    CYG_TEST_PASS_FAIL( EAGAIN == errno,
+                        "errno correct for non-blocking" );
+    
+    err = mq_send( q2, "foo", sizeof("foo"), 1 );
+    CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send on read-only descriptor" );
+    CYG_TEST_PASS_FAIL( EBADF == errno,
+                        "errno correct for mq_send on r/o descriptor" );
+    
+    err = mq_send( q2, "supercalifragilisticexpealidocious", 21, 2 );
+    CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send (message too long)" );
+    CYG_TEST_PASS_FAIL( EMSGSIZE == errno,
+                        "errno correct for mq_send (message too long)" );
+    
+    err = mq_send( q1, "", sizeof(""), 5 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send \"\"" );
+    
+    err = mq_send( q1, "I love Vik", sizeof("I love Vik"), 7 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send (different priority)" );
+    
+    err = mq_send( q1, "a lot!", sizeof("a lot!"), 7 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send (same priority)" );
+    
+    err = mq_send( q1, "Vik is a babe", sizeof("Vik is a babe"), 6 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send (middle priority)" );
+    
+    err = mq_send( q1, "wibble", sizeof("wibble"), 6 );
+    CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send with full queue" );
+    CYG_TEST_PASS_FAIL( EAGAIN == errno,
+                        "errno correct for mq_send full queue" );
+    
+    err = mq_getattr( q2, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after sends" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDONLY == (attr.mq_flags & O_RDONLY)) &&
+                        (O_WRONLY != (attr.mq_flags & O_WRONLY)) &&
+                        (O_RDWR != (attr.mq_flags & O_RDWR)) &&
+                        (4 == attr.mq_curmsgs ),
+                        "getattr attributes correct #5" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == sizeof("I love Vik"),
+                        "receive message length (prioritized) #1" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "I love Vik",
+                                        sizeof("I love Vik")),
+                        "received message data intact (prioritized) #1" );
+    CYG_TEST_PASS_FAIL( 7 == prio,
+                        "received at correct priority (prioritized) #1" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == sizeof("a lot!"),
+                        "receive message length (prioritized) #2" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "a lot!",
+                                        sizeof("a lot!")),
+                        "received message data intact (prioritized) #2" );
+    CYG_TEST_PASS_FAIL( 7 == prio,
+                        "received at correct priority (prioritized) #2" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is a babe"),
+                        "receive message length (prioritized) #3" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is a babe",
+                                        sizeof("Vik is a babe")),
+                        "received message data intact (prioritized) #3" );
+    CYG_TEST_PASS_FAIL( 6 == prio,
+                        "received at correct priority (prioritized) #3" );
+
+    recvlen = mq_receive( q2, buf, 0, &prio );
+    CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
+                        "mq_receive, zero-sized buffer" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == sizeof(""),
+                        "receive message length (prioritized) #4" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "",
+                                        sizeof("")),
+                        "received message data intact (prioritized) #4" );
+    CYG_TEST_PASS_FAIL( 5 == prio,
+                        "received at correct priority (prioritzed) #4" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1,
+                        "mq_receive, empty buffer, non-blocking #2" );
+    CYG_TEST_PASS_FAIL( EAGAIN == errno,
+                        "errno correct for non-blocking #2" );
+    
+    err = mq_send( q1, "12345678901234567890", 20, 15 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send (before closing)" );
+    
+    err = mq_unlink( "/foo" );
+    CYG_TEST_PASS_FAIL( -1 == err, "mq_unlink (wrong name)" );
+    CYG_TEST_PASS_FAIL( ENOENT == errno,
+                        "errno correct for mq_unlink (wrong name)" );
+
+    err = mq_unlink( "/mq1" );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink (before closing)" );
+
+    err = mq_close( q1 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_close (send descriptor)" );
+
+    recvlen = mq_receive( q2, buf, sizeof(buf), &prio );
+    CYG_TEST_PASS_FAIL( recvlen == 20,
+                        "receive message length (mid close)" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "12345678901234567890", 20 ),
+                        "received message data intact (mid close)" );
+    CYG_TEST_PASS_FAIL( 15 == prio,
+                        "received at correct priority (mid close)" );
+
+    err = mq_close( q2 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_close (receive descriptor)" );
+
+    q1 = mq_open( "/mq1", O_RDONLY );
+    CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" );
+    CYG_TEST_PASS_FAIL( ENOENT == errno,
+                        "errno correct for non-existent queue" );
+
+    CYG_TEST_EXIT("POSIX message test 1");
+
+    return 0;
+} // main()
+
+//------------------------------------------------------------------------
+
+#endif
+
+/* EOF pmqueue1.c */
diff --git a/packages/compat/posix/v2_0/tests/pmqueue2.c b/packages/compat/posix/v2_0/tests/pmqueue2.c
new file mode 100644 (file)
index 0000000..4f9c1b0
--- /dev/null
@@ -0,0 +1,276 @@
+/*========================================================================
+//
+//      pmqueue2.c
+//
+//      POSIX Message queues tests - mq_notify
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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.,
+// 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.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     jlarmour
+// Contributors:  
+// Date:          2000-05-18
+// Purpose:       This file provides tests for POSIX mqueue mq_notify
+// Description:   
+// Usage:         
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/* CONFIGURATION */
+
+#include <pkgconf/posix.h>
+
+#ifndef CYGPKG_POSIX_MQUEUES
+# define NA_MSG "Message queues not configured"
+#elif !defined(CYGPKG_POSIX_SIGNALS)
+# define NA_MSG "No POSIX signals configured"
+#endif
+
+#ifdef NA_MSG
+#include <cyg/infra/testcase.h>      // test API
+void
+cyg_user_start(void)
+{
+    CYG_TEST_INIT();
+    CYG_TEST_NA( NA_MSG );
+}
+
+#else
+
+/* INCLUDES */
+
+#include <fcntl.h>                   // O_*
+#include <errno.h>                   // errno
+#include <sys/stat.h>                // file modes
+#include <mqueue.h>                  // Mqueue Header
+#include <cyg/infra/testcase.h>      // test API
+#include <signal.h>                  // signals
+
+/* GLOBALS */
+sig_atomic_t signals=0;
+char buf[20];
+unsigned int prio;
+
+
+/* FUNCTIONS */
+
+static int
+my_memcmp(const void *m1, const void *m2, size_t n)
+{
+    char *s1 = (char *)m1;
+    char *s2 = (char *)m2;
+
+    while (n--) {
+        if (*s1 != *s2)
+            return *s1 - *s2;
+        s1++;
+        s2++;
+    }
+    return 0;
+} // my_memcmp()
+
+static char *
+my_strcpy(char *s1, const char *s2)
+{
+    char *s = s1;
+    while (*s2) {
+        *s1++ = *s2++;
+    }
+    return s;
+} // my_strcpy()
+
+static size_t
+my_strlen(const char *s)
+{
+    const char *start = s;
+    while (*s)
+        s++;
+    return (s - start);
+} // my_strcpy()
+
+
+
+//************************************************************************
+
+static void
+sigusr1_handler( int signo, siginfo_t *info, void *context )
+{
+    ssize_t recvlen;
+    char mybuf[20];
+    unsigned int myprio;
+    mqd_t *q = (mqd_t *)info->si_value.sival_ptr;
+
+    CYG_TEST_PASS_FAIL( SIGUSR1 == signo, "correct signal number #1" );
+    CYG_TEST_PASS_FAIL( SIGUSR1 == info->si_signo, "correct signal number #2" );
+    CYG_TEST_PASS_FAIL( SI_MESGQ == info->si_code, "correct signal code" );
+
+    signals++;
+
+    // retrieve message and compare with buf
+    recvlen = mq_receive( *q, mybuf, sizeof(mybuf), &myprio );
+    CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
+                        "receive message length" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
+                        "received message data intact" );
+    CYG_TEST_PASS_FAIL( prio == myprio,
+                        "received at correct priority" );
+}
+
+//************************************************************************
+
+int
+main(void)
+{
+    mqd_t q1;
+    struct mq_attr attr;
+    mode_t mode;
+    int err;
+    ssize_t recvlen;
+    char mybuf[20];
+    unsigned int myprio;
+    struct sigevent ev;
+    struct sigaction act;
+
+    CYG_TEST_INIT();
+    CYG_TEST_INFO( "Starting POSIX message test 2" );
+
+#if 0
+    if ( 0 != pthread_create( &thr, NULL, &thread, NULL ) ) {
+        CYG_TEST_FAIL_FINISH( "Couldn't create a helper thread" );
+    }
+#endif
+
+    attr.mq_flags = 0;
+    attr.mq_maxmsg = 4;
+    attr.mq_msgsize = 20;
+    mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all
+
+    q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_RDWR, mode, &attr );
+    CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" );
+    
+    err = mq_getattr( q1, &attr );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" );
+    CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) &&
+                        (20 == attr.mq_msgsize) &&
+                        (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) &&
+                        (O_RDWR == (attr.mq_flags & O_RDWR)) &&
+                        (0 == attr.mq_curmsgs ), "getattr attributes correct" );
+
+
+    act.sa_sigaction = &sigusr1_handler;
+    sigfillset( &act.sa_mask ); // enable all signals
+    act.sa_flags = SA_SIGINFO;
+    
+    if ( 0 != sigaction( SIGUSR1, &act, NULL ) ) {
+        CYG_TEST_FAIL_FINISH( "Couldn't register signal handler" );
+    }
+
+    ev.sigev_notify = SIGEV_SIGNAL;
+    ev.sigev_signo = SIGUSR1;
+    ev.sigev_value.sival_ptr = (void *)&q1;
+
+    err = mq_notify( q1, &ev );
+    CYG_TEST_PASS_FAIL( 0 == err, "simple mq_notify" );
+
+    my_strcpy( buf, "Vik is the best" );
+    prio = 7;
+    err = mq_send( q1, buf, my_strlen(buf), prio );
+
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send #1" );
+
+    CYG_TEST_PASS_FAIL( 1 == signals, "got notification" );
+
+    my_strcpy( buf, "Scrummy Vik" );
+    prio = 6;
+    err = mq_send( q1, buf, my_strlen(buf), prio );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" );
+
+    CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification" );
+
+    recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio );
+    CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
+                        "receive message length" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
+                        "received message data intact" );
+    CYG_TEST_PASS_FAIL( prio == myprio,
+                        "received at correct priority" );
+
+    err = mq_notify( q1, &ev );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_notify #2" );
+
+    err = mq_notify( q1, &ev );
+    CYG_TEST_PASS_FAIL( -1 == err, "second mq_notify returns error" );
+    CYG_TEST_PASS_FAIL( EBUSY == errno,
+                        "errno correct for second mq_notify error" );
+
+    err = mq_notify( q1, NULL );
+    CYG_TEST_PASS_FAIL( 0 == err, "clear notification" );
+
+    my_strcpy( buf, "Vik is k3wl" );
+    prio = 8;
+    err = mq_send( q1, buf, my_strlen(buf), prio );
+
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" );
+
+    CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification #2" );
+
+    recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio );
+    CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf),
+                        "receive message length" );
+    CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)),
+                        "received message data intact" );
+    CYG_TEST_PASS_FAIL( prio == myprio,
+                        "received at correct priority" );
+    
+    err = mq_close( q1 );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_close" );
+
+    err = mq_unlink( "/mq1" );
+    CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink" );
+
+    CYG_TEST_EXIT("POSIX message test 2");
+
+    return 0;
+} // main()
+
+//------------------------------------------------------------------------
+
+#endif
+
+/* EOF pmqueue2.c */
diff --git a/packages/compat/posix/v2_0/tests/pmutex3.c b/packages/compat/posix/v2_0/tests/pmutex3.c
new file mode 100644 (file)
index 0000000..7d712e1
--- /dev/null
@@ -0,0 +1,672 @@
+//==========================================================================
+//
+//        pmutex3.c
+//
+//        Mutex test 3 - priority inheritance
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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.,
+// 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.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     hmt
+// Contributors:  hmt, nickg, jlarmour
+// Date:          2000-01-06
+// Description:   Tests mutex priority inheritance. This is simply a translation
+//                of the similarly named kernel test to the POSIX API
+//####DESCRIPTIONEND####
+
+// ------------------------------------------------------------------------
+
+#include <cyg/infra/testcase.h>
+#include <pkgconf/posix.h>
+#include <pkgconf/system.h>
+#ifdef CYGPKG_KERNEL
+#include <pkgconf/kernel.h>
+#endif
+
+#ifdef CYGPKG_ISOINFRA
+# include <sys/types.h>
+# include <pthread.h>
+# include <semaphore.h>
+# include <time.h>
+# include <unistd.h>
+#endif
+
+#if !defined(CYGPKG_POSIX_PTHREAD)
+#define NA_MSG "POSIX threads not enabled"
+
+// ------------------------------------------------------------------------
+//
+// These checks should be enough; any other scheduler which has priorities
+// should manifest as having no priority inheritance, but otherwise fine,
+// so the test should work correctly.
+
+#elif !defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
+#define NA_MSG "No POSIX thread priority scheduling enabled"
+#elif !defined(_POSIX_THREAD_PRIO_INHERIT)
+#define NA_MSG "No POSIX thread priority inheritance enabled"
+#elif !defined(_POSIX_SEMAPHORES)
+#define NA_MSG "No POSIX sempaphore support enabled enabled"
+#elif !defined(CYGFUN_KERNEL_API_C)
+#define NA_MSG "Kernel C API not enabled"
+#elif defined(CYGPKG_KERNEL_SMP_SUPPORT)
+#define NA_MSG "Test cannot run with SMP support"
+#endif
+
+#ifdef NA_MSG
+void
+cyg_start(void)
+{
+    CYG_TEST_INIT();
+    CYG_TEST_NA(NA_MSG);
+}
+#else
+
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h>             // diag_printf
+
+#include <cyg/kernel/kapi.h>            // Some extras
+
+// ------------------------------------------------------------------------
+// Management functions
+//
+// Stolen from testaux.hxx and copied in here because I want to be able to
+// reset the world also.
+// ... and subsequently POSIXized out of all similarly with its progenitors.
+
+#define NTHREADS 7
+
+#define STACKSIZE (PTHREAD_STACK_MIN*2)
+
+static pthread_t thread[NTHREADS] = { 0 };
+
+typedef CYG_WORD64 CYG_ALIGNMENT_TYPE;
+
+static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
+   (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
+     / sizeof(CYG_ALIGNMENT_TYPE)                     ];
+
+// Semaphores to halt execution of threads     
+static sem_t hold[NTHREADS];
+
+// Flag to tell all threads to exit
+static int all_exit;
+
+// Application thread data is passed here, the thread
+// argument is 
+static CYG_ADDRWORD thread_data[NTHREADS];
+
+static volatile int nthreads = 0;
+
+// Sleep for 1 tick...
+static struct timespec sleeptime;
+
+
+static pthread_t new_thread( void *(*entry)(void *),
+                             CYG_ADDRWORD data,
+                             int priority,
+                             int do_resume)
+{
+    pthread_attr_t attr;
+    int _nthreads = nthreads++;
+
+    struct sched_param schedparam;
+    schedparam.sched_priority = priority;
+        
+    pthread_attr_init( &attr );
+    pthread_attr_setstackaddr( &attr, (void *)((char *)(&stack[_nthreads])+STACKSIZE) );        
+    pthread_attr_setstacksize( &attr, STACKSIZE );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    CYG_ASSERT(_nthreads < NTHREADS, 
+               "Attempt to create more than NTHREADS threads");
+
+    thread_data[_nthreads] = data;
+
+    sem_init( &hold[_nthreads], 0, do_resume ? 1 : 0 );
+    all_exit = 0;
+
+    pthread_create( &thread[_nthreads],
+                    &attr,
+                    entry,
+                    (void *)_nthreads);
+
+    return thread[_nthreads];
+}
+
+
+static void kill_threads( void )
+{
+    CYG_ASSERT(nthreads <= NTHREADS, 
+               "More than NTHREADS threads");
+    CYG_ASSERT( pthread_equal(pthread_self(),thread[0]),
+                "kill_threads() not called from thread 0");
+    all_exit = 1;
+    while ( nthreads > 1 ) {
+        nthreads--;
+        if ( 0 != thread[nthreads] ) {
+            sem_post( &hold[nthreads] );
+            pthread_cancel( thread[nthreads] );
+            pthread_join( thread[nthreads], NULL );
+            thread[nthreads] = 0;
+            sem_destroy( &hold[nthreads] );
+        }
+    }
+    CYG_ASSERT(nthreads == 1,
+               "No threads left");
+}
+
+// ------------------------------------------------------------------------
+
+#define DELAYFACTOR 1 // for debugging
+
+// ------------------------------------------------------------------------
+
+pthread_mutex_t mutex;
+
+// These are for reporting back to the master thread
+volatile int got_it  = 0;
+volatile int t3ran   = 0;
+volatile int t3ended = 0;
+volatile int extras[4] = {0,0,0,0};
+    
+volatile int go_flag = 0; // but this one controls thread 3 from thread 2
+
+// ------------------------------------------------------------------------
+// 0 to 3 of these run generally to interfere with the other processing,
+// to cause multiple prio inheritances, and clashes in any orders.
+
+static void *extra_thread( void *arg )
+{
+#define XINFO( z ) \
+    do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 )
+
+    static char running[]  = "Extra thread Xa running";
+    static char exiting[]  = "Extra thread Xa exiting";
+    static char resumed[]  = "Extra thread Xa resumed";
+    static char locked[]   = "Extra thread Xa locked";
+    static char unlocked[] = "Extra thread Xa unlocked";
+
+    int id = (int)arg;
+    CYG_ADDRWORD data = thread_data[id];
+
+    CYG_ASSERT( (id >= 4 && id <= 6), "extra_thread invalid id" );
+    
+    // Emulate resume behaviour
+    sem_wait( &hold[id] );
+    if( all_exit ) return 0;
+    
+    XINFO( running );
+
+    sem_wait( &hold[id] );
+    
+    XINFO( resumed );
+
+    pthread_mutex_lock( &mutex );
+
+    XINFO( locked );
+
+    pthread_mutex_unlock( &mutex );    
+
+    XINFO( unlocked );
+
+    extras[ data ] ++;
+
+    XINFO( exiting );
+
+    return NULL;
+}
+
+// ------------------------------------------------------------------------
+
+static void *t1( void *arg )
+{
+    int id = (int)arg;
+    //CYG_ADDRWORD data = thread_data[id];
+    
+    // Emulate resume behaviour
+    sem_wait( &hold[id] );
+    if( all_exit ) return 0;
+
+    CYG_TEST_INFO( "Thread 1 running" );
+
+    sem_wait( &hold[id] );    
+
+    pthread_mutex_lock( &mutex );
+
+    got_it++;
+
+    CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" );
+
+    pthread_mutex_unlock( &mutex );
+
+    CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" );
+
+    // That's all.
+
+    CYG_TEST_INFO( "Thread 1 exit" );
+
+    return 0;    
+}
+
+// ------------------------------------------------------------------------
+
+static void *t2( void *arg )
+{
+    int i;
+    int id = (int)arg;
+    CYG_ADDRWORD data = thread_data[id];
+    cyg_tick_count_t now, then;
+    
+    // Emulate resume behaviour
+    sem_wait( &hold[id] );
+    if( all_exit ) return 0;
+
+    CYG_TEST_INFO( "Thread 2 running" );
+
+    CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" );
+    CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" );
+
+    sem_wait( &hold[id] );
+
+    // depending on our config argument, optionally restart some of the
+    // extra threads to throw noise into the scheduler:
+    for ( i = 0; i < 3; i++ )
+        if ( (1 << i) & data )          // bits 0-2 control
+            sem_post( &hold[i+4] );     // made sure extras are thread[4-6]
+
+    // let those threads run
+    for( i = 0; i < DELAYFACTOR * 10; i++ )
+        nanosleep( &sleeptime, NULL );
+
+    cyg_scheduler_lock();               // do this next lot atomically
+
+    go_flag = 1;                        // unleash thread 3
+    sem_post( &hold[1] );               // resume thread 1
+
+    // depending on our config argument, optionally restart some of the
+    // extra threads to throw noise into the scheduler at this later point:
+    for ( i = 4; i < 7; i++ )
+        if ( (1 << i) & data )          // bits 4-6 control
+            sem_post( &hold[i] );       // made sure extras are thread[4-6]
+
+    cyg_scheduler_unlock();             // let scheduling proceed
+
+    // Need a delay (but not a CPU yield) to allow t3 to awaken and act on
+    // the go_flag, otherwise we check these details below too soon.
+    // Actually, waiting for the clock to tick a couple of times would be
+    // better, so that is what we will do.  Must be a busy-wait.
+    then = cyg_current_time();
+    do {
+        now = cyg_current_time();
+        // Wait longer than the delay in t3 waiting on go_flag
+    } while ( now < (then + 3) );
+
+#ifdef _POSIX_THREAD_PRIO_INHERIT
+    CYG_TEST_INFO( "Checking for mutex priority inheritance" );
+    CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+    CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+#else
+    CYG_TEST_INFO( "Checking for NO mutex priority inheritance" );
+    CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" );
+    CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" );
+#endif
+
+    CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" );
+
+    for( i = 0; i < DELAYFACTOR * 20; i++ )    
+        nanosleep( &sleeptime, NULL );      // let those threads run  
+
+    CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+    CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+    CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" );
+
+    for ( i = 0; i < 3; i++ )
+        if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control
+            CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" );
+        else
+            CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" );
+
+    CYG_TEST_PASS( "Thread 2 exiting, AOK" );
+    // That's all: restart the control thread.
+    sem_post( &hold[0] );
+
+    return 0;    
+}
+
+// ------------------------------------------------------------------------
+
+static void *t3( void *arg )
+{
+    int i;
+    int id = (int)arg;
+    //CYG_ADDRWORD data = thread_data[id];
+    
+    // Emulate resume behaviour
+    sem_wait( &hold[id] );
+    if( all_exit ) return 0;
+    
+    CYG_TEST_INFO( "Thread 3 running" );
+
+    pthread_mutex_lock( &mutex );
+
+    for( i = 0; i < DELAYFACTOR * 5; i++ )    
+        nanosleep( &sleeptime, NULL );      // let thread 3a run
+
+    sem_post( &hold[2] );               // resume thread 2
+
+    while ( 0 == go_flag )
+        nanosleep( &sleeptime, NULL );  // wait until we are told to go
+
+    t3ran ++;                           // record the fact
+
+    CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" );
+
+    pthread_mutex_unlock( &mutex );
+
+    t3ended ++;                         // record that we came back
+
+    CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+
+    CYG_TEST_INFO( "Thread 3 exit" );
+
+    return 0;
+}
+
+// ------------------------------------------------------------------------
+
+static void *control_thread( void *arg )
+{
+    int i,z;
+    int id = (int)arg;
+    //CYG_ADDRWORD data = thread_data[id];
+    
+    // Emulate resume behaviour
+    sem_wait( &hold[id] );
+    if( all_exit ) return 0;
+    
+    // one tick sleep time
+    sleeptime.tv_nsec = 10000000;
+    sleeptime.tv_sec = 0;
+    
+    CYG_TEST_INIT();
+    CYG_TEST_INFO( "Control Thread running" );
+
+    // Go through the 27 possibilitied of resuming the extra threads
+    //     0: not at all
+    //     1: early in the process
+    //     2: later on
+    // which are represented by bits 0-3 and 4-6 resp in the argument to
+    // thread 2 (none set means no resume at all).
+    for ( i = 0; i < 27; i++ ) {
+        static int xx[] = { 0, 1, 16 };
+        int j = i % 3;
+        int k = (i / 3) % 3;
+        int l = (i / 9) % 3;
+
+        int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ;
+
+        if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) )
+            continue;    // 13 is 111 base 3, 26 is 222 base 3
+
+#ifdef _POSIX_THREAD_PRIO_INHERIT
+        // If the simple scheme plus relay enhancement, or any other
+        // *complete* scheme, we can run all three ancillary threads no
+        // problem, so no special action here.
+
+#else
+        // If no priority inheritance at all, running threads 1a and 2a is
+        // OK, but not thread 3a; it blocks the world.
+        if ( l )                        // Cannot run thread 3a if no
+            break;                      //     priority inheritance at all.
+#endif
+
+        // Reinitialize mutex to provide priority inheritance
+        {
+            pthread_mutexattr_t attr;
+            pthread_mutexattr_init( &attr );
+            pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT );
+            pthread_mutex_init( &mutex, &attr );
+        }
+
+        got_it  = 0;
+        t3ran   = 0;
+        t3ended = 0;
+        for ( z = 0; z < 4; z++ ) extras[z] = 0;
+        go_flag = 0;
+        
+        new_thread( t1, 0, 15, 1 );            // Slot 1
+        new_thread( t2, d, 10, 1 );            // Slot 2
+        new_thread( t3, 0,  5, 1 );            // Slot 3
+        
+        new_thread( extra_thread, 1, 17, j );  // Slot 4
+        new_thread( extra_thread, 2, 12, k );  // Slot 5
+        new_thread( extra_thread, 3,  8, l );  // Slot 6
+        
+        {
+            static char *a[] = { "inactive", "run early", "run late" };
+            diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n",
+                         i, d,  a[j], a[k], a[l] );
+        }
+
+        sem_wait( &hold[0] );
+        
+        kill_threads();
+        pthread_mutex_destroy( &mutex );
+    }
+    CYG_TEST_EXIT( "Control Thread exit" );
+
+    return 0;
+}
+
+// ------------------------------------------------------------------------
+
+static sem_t main_sem;
+
+externC int
+main( int argc, char **argv )
+{ 
+    new_thread( control_thread, 0, 20, 1 );
+
+    // We have nothing for main to do here, so put it to sleep on
+    // its own semaphore. We cannot let it just exit since that
+    // will end the whole program.
+
+    sem_init( &main_sem, 0, 0 );
+    
+    for(;;) sem_wait( &main_sem );
+}
+
+// ------------------------------------------------------------------------
+// Documentation: enclosed is the design of this test.
+//
+// It has been carefully constructed so that it does NOT use other kernel
+// facilities (aside from delay-task) to test that priority inheritance is
+// working, or not, as intended by the configuration.
+//
+// These notes describe the flow of control in one run of the test with the
+// ancillary tasks optionally interspersed.  The details of how those extra
+// tasks are or are not allowed to run are not described.
+// 
+// 
+// 
+// The only change in the test that depends on whether there is inheritance or
+// not is the check in thread 2 on "3-ran" and "got it" flags marked ****
+// 
+// 
+// volatile &c booleans:
+//         "got it"     = FALSE
+//         "3-ran"      = FALSE
+//         "3-ended"    = FALSE
+//         "extras"[3]  = FALSE
+// 
+// thread 1.  prio 5, self-suspend.
+// 
+// thread 1a, prio 8, self-suspend.
+// 
+// thread 2.  prio 10, self-suspend.
+// 
+// thread 2a, prio 12, self-suspend.
+// 
+// thread 3.  prio 15, runs, lock mutex, resume(2)
+// 
+// thread 3a, prio 17, self-suspend.
+// 
+//        2.  runs,
+//        2.  resume(3a) +++OPTIONAL
+//        2.  resume(2a) +++OPTIONAL
+//        2.  resume(1a) +++OPTIONAL
+//        [1a lock-fail]       thread 3->prio := 8
+// 
+//        [3. runs maybe, does the looping thing]
+// 
+//        2.  sleep a while...
+// 
+//        [2a lock-fail]       thread 3->prio := 12
+// 
+//        [3. runs maybe, does the looping thing]
+// 
+//        [3a lock-fail]   thread 3->prio unchanged
+// 
+//        [3. runs maybe, does the looping thing]
+// 
+//        2.  lock scheduler
+//        2.  set "go-flag"
+//        2.  resume(1)
+//        2.  resume(1a) +++OPTIONAL
+//        2.  resume(2a) +++OPTIONAL
+//        2.  resume(3a) +++OPTIONAL
+//        2.  unlock scheduler
+// 
+//        1.  runs, lock mutex - thread 3 has it locked
+//
+//        2.  busy-waits a bit for thread 3 to come out of its delay() loop.
+//            This must be a *busy*wait so that 3 can only run via the
+//            inherited raised priority.
+// 
+//        [xa. all do the same: lock mutex,                ]
+//        [xa. unlock mutex                                ]
+//        [xa. set a flag "extras"[x] to say we are done.  ]
+//        [xa. exit                                        ]
+// 
+// 
+// 
+// INHERIT
+// -------
+// 
+//                 thread 3->prio := 5
+// 
+//        3.  runs,
+//        3.  set a flag to say "3-ran",
+//        3.  loop with a sleep(1) until "go-flag" is set.
+//        3.  check "got it" is false,
+//        3.  then unlock mutex,
+// 
+//                 thread 3->prio := 15
+// 
+//        1.  runs, set a flag to say "got it",
+//        1.  check "3-ended" flag is false
+//        1.  unlock mutex,
+//        1.  check "3-ended" flag is still false
+//        1.  exit.
+// 
+//        [1a locks, unlocks, exits]
+// 
+//        2.  runs, check "3-ran" and "got it" flags are TRUE ****
+//        2.  check "3-ended" flag is false
+//        2.  sleeps for a while so that...
+// 
+//        [2a locks, unlocks, exits]
+//            
+//        3.  runs, set "3-ended" flag,
+//        3.  check "3-ran" and "got it" flags
+//        3.  exit
+// 
+//        [3a locks, unlocks, exits]
+// 
+//        2.  awakens, checks all flags true,
+//        2.  check that all "extra" threads that we started have indeed run
+//        2.  end of test.
+// 
+// 
+// 
+// 
+// NO-INHERIT
+// ----------
+//                 thread 1 is waiting on the mutex
+// 
+//        [1a lock-fail]
+// 
+//        2.  runs, checks that "3-ran" and "got it" flags are FALSE ****
+//        2.  check "3-ended" flag is false
+//        2.  sleeps for a while so that...
+// 
+//        [2a. lock-fail]
+//            
+//        3.  runs, set a flag to say "3-ran",
+//        3.  check "got it" is false,
+//        3.  then unlock mutex,
+// 
+//        1.  runs, set a flag to say "got it",
+//        1.  check "3-ended" flag is false
+//        1.  unlock mutex,
+//        1.  check "3-ended" flag is still false
+//        1.  exit.
+// 
+//        [1a locks, unlocks, exits]
+//        [2a locks, unlocks, exits]
+// 
+//        3.  runs, set "3-ended" flag,
+//        3.  check "3-ran" and "got it" flags
+//        3.  exit
+// 
+//        [3a locks, unlocks, exits]
+//                
+//        2.  awakens, checks all flags true, 
+//        2.  check that all "extra" threads that we started have indeed run
+//        2.  end of test.
+// 
+// 
+// (the end)
+// 
+// 
+// ------------------------------------------------------------------------
+
+#endif
+
+// EOF pmutex3.c
diff --git a/packages/compat/posix/v2_0/tests/tm_posix.cxx b/packages/compat/posix/v2_0/tests/tm_posix.cxx
new file mode 100644 (file)
index 0000000..34154e2
--- /dev/null
@@ -0,0 +1,1714 @@
+//==========================================================================
+//
+//        tm_posix.cxx
+//
+//        Basic timing test / scaffolding
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Jonathan Larmour
+//
+// 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.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     gthomas,nickg
+// Contributors:  jlarmour
+// Date:          1998-10-19
+// Description:   Very simple kernel timing test
+//####DESCRIPTIONEND####
+//==========================================================================
+
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+#include <pkgconf/posix.h>
+#include <pkgconf/system.h>
+#ifdef CYGPKG_KERNEL
+#include <pkgconf/kernel.h>
+#endif
+
+#ifndef CYGPKG_POSIX_SIGNALS
+#define NA_MSG "No POSIX signals"
+#elif !defined(CYGPKG_POSIX_TIMERS)
+#define NA_MSG "No POSIX timers"
+#elif !defined(CYGPKG_POSIX_PTHREAD)
+#define NA_MSG "POSIX threads not enabled"
+#elif !defined(CYGFUN_KERNEL_API_C)
+#define NA_MSG "Kernel C API not enabled"
+#elif !defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
+#define NA_MSG "Kernel mlqueue scheduler not enabled"
+#elif !defined(CYGVAR_KERNEL_COUNTERS_CLOCK)
+#define NA_MSG "Kernel clock not enabled"
+#elif CYGNUM_KERNEL_SCHED_PRIORITIES <= 12
+#define NA_MSG "Kernel scheduler properties <= 12"
+#elif !defined(CYGPKG_POSIX_SEMAPHORES)
+#define NA_MSG "POSIX semaphores not enabled"
+#endif
+
+//==========================================================================
+
+#ifdef NA_MSG
+extern "C" void
+cyg_start(void)
+{
+    CYG_TEST_INIT();
+    CYG_TEST_NA(NA_MSG);
+}
+#else
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/test/stackmon.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+
+// POSIX headers
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+
+//==========================================================================
+// Define this to see the statistics with the first sample datum removed.
+// This can expose the effects of caches on the speed of operations.
+
+#undef STATS_WITHOUT_FIRST_SAMPLE
+
+//==========================================================================
+
+// Structure used to keep track of times
+typedef struct fun_times {
+    cyg_uint32 start;
+    cyg_uint32 end;
+} fun_times;
+
+//==========================================================================
+
+#define STACK_SIZE (PTHREAD_STACK_MIN*2)
+
+// Defaults
+#define NTEST_THREADS    16
+#define NMUTEXES         32
+#define NMBOXES          32
+#define NSEMAPHORES      32
+#define NTIMERS          32
+
+
+#define NSAMPLES         32
+#define NTHREAD_SWITCHES 128
+#define NSCHEDS          128
+
+#define NSAMPLES_SIM         2
+#define NTEST_THREADS_SIM    2
+#define NTHREAD_SWITCHES_SIM 4
+#define NMUTEXES_SIM         2
+#define NMBOXES_SIM          2
+#define NSEMAPHORES_SIM      2
+#define NSCHEDS_SIM          4
+#define NTIMERS_SIM          2
+
+//==========================================================================
+
+static int nsamples;
+static int ntest_threads;
+static int nthread_switches;
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+static int nmutexes;
+#endif
+static int nmboxes;
+static int nsemaphores;
+static int nscheds;
+static int ntimers;
+
+static char stacks[NTEST_THREADS][STACK_SIZE];
+static pthread_t threads[NTEST_THREADS];
+static int overhead;
+static sem_t synchro;
+static fun_times thread_ft[NTEST_THREADS];
+
+static fun_times test2_ft[NTHREAD_SWITCHES];
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+static pthread_mutex_t test_mutexes[NMUTEXES];
+static fun_times mutex_ft[NMUTEXES];
+static pthread_t mutex_test_thread_handle;
+#endif
+#if 0
+static cyg_mbox test_mboxes[NMBOXES];
+static cyg_handle_t test_mbox_handles[NMBOXES];
+static fun_times mbox_ft[NMBOXES];
+static cyg_thread mbox_test_thread;
+static cyg_handle_t mbox_test_thread_handle;
+#endif
+
+static sem_t test_semaphores[NSEMAPHORES];
+static fun_times semaphore_ft[NSEMAPHORES];
+static pthread_t semaphore_test_thread_handle;
+
+static fun_times sched_ft[NSCHEDS];
+
+static timer_t timers[NTIMERS];
+static fun_times timer_ft[NTIMERS];
+
+static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+static long ns_per_system_clock;
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY)
+// Data kept by kernel real time clock measuring clock interrupt latency
+extern cyg_tick_count total_clock_latency, total_clock_interrupts;
+extern cyg_int32 min_clock_latency, max_clock_latency;
+extern bool measure_clock_latency;
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
+extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
+extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency;
+extern bool measure_clock_latency;
+#endif
+
+//==========================================================================
+
+void run_sched_tests(void);
+void run_thread_tests(void);
+void run_thread_switch_test(void);
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+void run_mutex_tests(void);
+void run_mutex_circuit_test(void);
+#endif
+void run_mbox_tests(void);
+void run_mbox_circuit_test(void);
+void run_semaphore_tests(void);
+void run_semaphore_circuit_test(void);
+void run_timer_tests(void);
+
+//==========================================================================
+
+#ifndef max
+#define max(n,m) (m > n ? n : m)
+#endif
+
+//==========================================================================
+// Wait until a clock tick [real time clock] has passed.  This should keep it
+// from happening again during a measurement, thus minimizing any fluctuations
+void
+wait_for_tick(void)
+{
+    cyg_tick_count_t tv0, tv1;
+    tv0 = cyg_current_time();
+    while (true) {
+        tv1 = cyg_current_time();
+        if (tv1 != tv0) break;
+    }
+}
+
+//--------------------------------------------------------------------------
+// Display a number of ticks as microseconds
+// Note: for improved calculation significance, values are kept in ticks*1000
+void
+show_ticks_in_us(cyg_uint32 ticks)
+{
+    long long ns;
+    ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+    ns += 5;  // for rounding to .01us
+    diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
+}
+
+//--------------------------------------------------------------------------
+//
+// If the kernel is instrumented to measure clock interrupt latency, these
+// measurements can be drastically perturbed by printing via "diag_printf()"
+// since that code may run with interrupts disabled for long periods.
+//
+// In order to get accurate/reasonable latency figures _for the kernel 
+// primitive functions beint tested_, the kernel's latency measurements
+// are suspended while the printing actually takes place.
+//
+// The measurements are reenabled after the printing, thus allowing for
+// fair measurements of the kernel primitives, which are not distorted
+// by the printing mechanisms.
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+void
+disable_clock_latency_measurement(void)
+{
+    wait_for_tick();
+    measure_clock_latency = false;
+}
+
+void
+enable_clock_latency_measurement(void)
+{
+    wait_for_tick();
+    measure_clock_latency = true;
+}
+
+// Ensure that the measurements are reasonable (no startup anomalies)
+void
+reset_clock_latency_measurement(void)
+{
+  disable_clock_latency_measurement();
+  total_clock_latency = 0;
+  total_clock_interrupts = 0;
+  min_clock_latency = 0x7FFFFFFF;
+  max_clock_latency = 0;
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)  
+  total_clock_dsr_latency = 0;
+  total_clock_dsr_calls = 0;
+  min_clock_dsr_latency = 0x7FFFFFFF;
+  max_clock_dsr_latency = 0;
+#endif  
+  enable_clock_latency_measurement();
+  
+}
+#else
+#define disable_clock_latency_measurement()
+#define enable_clock_latency_measurement()
+#define reset_clock_latency_measurement()
+#endif
+
+//--------------------------------------------------------------------------
+
+void
+show_times_hdr(void)
+{
+    disable_clock_latency_measurement();
+    diag_printf("\n");
+    diag_printf("                                 Confidence\n");
+    diag_printf("     Ave     Min     Max     Var  Ave  Min  Function\n");
+    diag_printf("  ======  ======  ======  ====== ========== ========\n");
+    enable_clock_latency_measurement();
+}
+
+void
+show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first)
+{
+    int i, delta, min, max, con_ave, con_min, ave_dev;
+    int start_sample, total_samples;   
+    cyg_int32 total, ave;
+
+    if (ignore_first) {
+        start_sample = 1;
+        total_samples = nsamples-1;
+    } else {
+        start_sample = 0;
+        total_samples = nsamples;
+    }
+    total = 0;
+    min = 0x7FFFFFFF;
+    max = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        delta *= 1000;
+        total += delta;
+        if (delta < min) min = delta;
+        if (delta > max) max = delta;
+    }
+    ave = total / total_samples;
+    total = 0;
+    ave_dev = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        delta *= 1000;
+        delta = delta - ave;
+        if (delta < 0) delta = -delta;
+        ave_dev += delta;
+    }
+    ave_dev /= total_samples;
+    con_ave = 0;
+    con_min = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        delta *= 1000;
+        if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++;
+        if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++;
+    }
+    con_ave = (con_ave * 100) / total_samples;
+    con_min = (con_min * 100) / total_samples;
+    show_ticks_in_us(ave);
+    show_ticks_in_us(min);
+    show_ticks_in_us(max);
+    show_ticks_in_us(ave_dev);
+    disable_clock_latency_measurement();
+    diag_printf("  %3d%% %3d%%", con_ave, con_min);
+    diag_printf(" %s\n", title);
+    enable_clock_latency_measurement();
+}
+
+void
+show_times(fun_times ft[], int nsamples, char *title)
+{
+    show_times_detail(ft, nsamples, title, false);
+#ifdef STATS_WITHOUT_FIRST_SAMPLE
+    show_times_detail(ft, nsamples, "", true);
+#endif
+}
+
+//--------------------------------------------------------------------------
+
+void
+show_test_parameters(void)
+{
+    disable_clock_latency_measurement();
+    diag_printf("\nTesting parameters:\n");
+    diag_printf("   Clock samples:         %5d\n", nsamples);
+    diag_printf("   Threads:               %5d\n", ntest_threads);
+    diag_printf("   Thread switches:       %5d\n", nthread_switches);
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+    diag_printf("   Mutexes:               %5d\n", nmutexes);
+#endif
+    diag_printf("   Mailboxes:             %5d\n", nmboxes);
+    diag_printf("   Semaphores:            %5d\n", nsemaphores);
+    diag_printf("   Scheduler operations:  %5d\n", nscheds);
+    diag_printf("   Timers:                %5d\n", ntimers);
+    diag_printf("\n"); 
+    enable_clock_latency_measurement();
+}
+
+void
+end_of_test_group(void)
+{
+    disable_clock_latency_measurement();
+    diag_printf("\n"); 
+    enable_clock_latency_measurement();
+}
+
+//--------------------------------------------------------------------------
+// Compute a name for a thread
+
+char *
+thread_name(char *basename, int indx) {
+    return "<<NULL>>";  // Not currently used
+}
+
+//--------------------------------------------------------------------------
+// test0 - null test, just return
+
+void *
+test0(void *indx)
+{
+    return indx;
+}
+
+//--------------------------------------------------------------------------
+// test3 - loop, yeilding repeatedly and checking for cancellation
+
+void *
+test3(void *indx)
+{
+    for(;;)
+    {
+        sched_yield();
+        pthread_testcancel();
+    }
+    
+    return indx;
+}
+
+//--------------------------------------------------------------------------
+// test1 - empty test, simply exit.  Last thread signals parent.
+
+void *
+test1( void *indx)
+{
+    if ((cyg_uint32)indx == (cyg_uint32)(ntest_threads-1)) {
+        sem_post(&synchro);  // Signal that last thread is dying
+    }
+    return indx;
+}
+
+//--------------------------------------------------------------------------
+// test2 - measure thread switch times
+
+void *
+test2(void *indx)
+{
+    int i;
+    for (i = 0;  i < nthread_switches;  i++) {
+        if ((int)indx == 0) {
+            HAL_CLOCK_READ(&test2_ft[i].start);
+        } else {
+            HAL_CLOCK_READ(&test2_ft[i].end);
+        }
+        sched_yield();
+    }
+    if ((int)indx == 1) {
+        sem_post(&synchro);
+    }
+
+    return indx;
+}
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+//--------------------------------------------------------------------------
+// Full-circuit mutex unlock/lock test
+
+void *
+mutex_test(void * indx)
+{
+    int i;
+    pthread_mutex_lock(&test_mutexes[0]);
+    for (i = 0;  i < nmutexes;  i++) {
+        sem_wait(&synchro);
+        wait_for_tick(); // Wait until the next clock tick to minimize aberations
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_unlock(&test_mutexes[0]);
+        pthread_mutex_lock(&test_mutexes[0]);
+        sem_post(&synchro);
+    }
+    return indx;
+}
+
+//--------------------------------------------------------------------------
+// Full-circuit mbox put/get test
+
+#if 0
+void
+mbox_test(cyg_uint32 indx)
+{
+    void *item;
+    do {
+        item = cyg_mbox_get(test_mbox_handles[0]);
+        HAL_CLOCK_READ(&mbox_ft[(int)item].end);
+        cyg_semaphore_post(&synchro);
+    } while ((int)item != (nmboxes-1));
+    cyg_thread_exit(0);
+}
+#endif
+#endif
+//--------------------------------------------------------------------------
+// Full-circuit semaphore post/wait test
+
+void *
+semaphore_test(void * indx)
+{
+    int i;
+    for (i = 0;  i < nsemaphores;  i++) {
+        sem_wait(&test_semaphores[0]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+        sem_post(&synchro);
+    }
+    return indx;
+}
+
+//--------------------------------------------------------------------------
+//
+// This set of tests is used to measure kernel primitives that deal with threads
+//
+
+void
+run_thread_tests(void)
+{
+
+    
+    int i;
+    struct sched_param schedparam;
+    pthread_attr_t attr;
+    int policy;
+    void *retval;
+    
+    // Set my priority higher than any I plan to create
+    schedparam.sched_priority = 30;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+
+    // Initiaize thread creation attributes
+
+    pthread_attr_init( &attr );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        pthread_create( &threads[i],
+                        &attr,
+                        test0,
+                        (void *)i
+                        );
+        
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Create thread");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        sched_yield();
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Yield thread [all lower priority]");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+
+        schedparam.sched_priority = 11;
+        pthread_attr_setschedparam( &attr, &schedparam );
+        pthread_setschedparam(threads[i], SCHED_RR, &schedparam);
+
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Set priority");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        pthread_getschedparam( threads[i], &policy, &schedparam );
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Get priority");
+
+    cyg_thread_delay(1);        // Let the test threads run
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        pthread_join(threads[i], &retval);
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Join exited thread");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        sched_yield();
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Yield [no other] thread");
+
+    
+    // Recreate the test set
+
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    for (i = 0;  i < ntest_threads;  i++) {
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        pthread_create( &threads[i],
+                        &attr,
+                        test3,
+                        (void *)i
+                        );
+    }
+
+    cyg_thread_delay(1);        // Let the test threads run    
+    
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        pthread_cancel(threads[i]);
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Cancel [running] thread");
+
+    cyg_thread_delay(1);        // Let the test threads do their cancellations
+    
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+        pthread_join(threads[i], &retval);
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Join [cancelled] thread");
+
+    
+    // Set my priority lower than any I plan to create
+    schedparam.sched_priority = 5;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+    
+    // Set up the end-of-threads synchronizer
+    sem_init(&synchro, 0, 0);
+
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntest_threads;  i++) {
+        HAL_CLOCK_READ(&thread_ft[i].start);
+
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        pthread_create( &threads[i],
+                        &attr,
+                        test2,
+                        (void *)i
+                        );
+        
+        HAL_CLOCK_READ(&thread_ft[i].end);
+    }
+    show_times(thread_ft, ntest_threads, "Create [high priority] thread");
+
+    sem_wait(&synchro);  // Wait for all threads to finish
+
+    // Make sure they are all dead
+    for (i = 0;  i < ntest_threads;  i++) {
+        pthread_join(threads[i], &retval);
+    }
+
+    run_thread_switch_test();
+    end_of_test_group();
+
+}
+
+//--------------------------------------------------------------------------
+
+void
+run_thread_switch_test(void)
+{
+
+    int i;
+    struct sched_param schedparam;
+    pthread_attr_t attr;
+    void *retval;
+
+    // Set my priority higher than any I plan to create
+    schedparam.sched_priority = 30;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+
+    // Initiaize thread creation attributes
+
+    pthread_attr_init( &attr );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    // Set up the end-of-threads synchronizer
+
+    sem_init(&synchro, 0, 0);
+        
+    // Set up for thread context switch 
+
+    for (i = 0;  i < 2;  i++) {
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        pthread_create( &threads[i],
+                        &attr,
+                        test2,
+                        (void *)i
+                        );
+    }
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations    
+    
+    sem_wait(&synchro);
+
+    show_times(test2_ft, nthread_switches, "Thread switch");
+
+    // Clean up
+    for (i = 0;  i < 2;  i++) {
+        pthread_join(threads[i], &retval);
+    }
+
+}
+
+
+//--------------------------------------------------------------------------
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+void
+run_mutex_tests(void)
+{
+
+    int i;
+    pthread_mutexattr_t attr;
+
+    pthread_mutexattr_init( &attr );
+    
+    // Mutex primitives
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_init(&test_mutexes[i], &attr);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Init mutex");
+
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_lock(&test_mutexes[i]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_unlock(&test_mutexes[i]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Unlock [locked] mutex");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_trylock(&test_mutexes[i]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_trylock(&test_mutexes[i]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Trylock [locked] mutex");
+
+    // Must unlock mutices before destroying them.
+    for (i = 0;  i < nmutexes;  i++) {
+        pthread_mutex_unlock(&test_mutexes[i]);
+    }
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmutexes;  i++) {
+        HAL_CLOCK_READ(&mutex_ft[i].start);
+        pthread_mutex_destroy(&test_mutexes[i]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+    }
+    show_times(mutex_ft, nmutexes, "Destroy mutex");
+
+
+    run_mutex_circuit_test();
+    end_of_test_group();
+}
+
+//--------------------------------------------------------------------------
+
+void
+run_mutex_circuit_test(void)
+{
+    int i;
+    pthread_mutexattr_t mattr;
+    struct sched_param schedparam;
+    pthread_attr_t attr;
+    void *retval;
+
+    // Set my priority lower than any I plan to create
+    schedparam.sched_priority = 5;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+
+    // Initiaize thread creation attributes
+
+    pthread_attr_init( &attr );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    // Set up for full mutex unlock/lock test
+    pthread_mutexattr_init( &mattr );    
+    pthread_mutex_init(&test_mutexes[0], &mattr);
+    sem_init(&synchro, 0, 0);
+
+    pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
+    pthread_attr_setstacksize( &attr, STACK_SIZE );
+    pthread_create( &mutex_test_thread_handle,
+                    &attr,
+                    mutex_test,
+                    (void *)0
+        );
+    
+    // Need to raise priority so that this thread will block on the "lock"
+    schedparam.sched_priority = 20;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+    
+    for (i = 0;  i < nmutexes;  i++) {
+        sem_post(&synchro);
+        pthread_mutex_lock(&test_mutexes[0]);
+        HAL_CLOCK_READ(&mutex_ft[i].end);
+        pthread_mutex_unlock(&test_mutexes[0]);
+        sem_wait(&synchro);
+    }
+    pthread_join(mutex_test_thread_handle, &retval);
+    show_times(mutex_ft, nmutexes, "Unlock/Lock mutex");
+
+}
+
+#endif
+//--------------------------------------------------------------------------
+// Message queue tests
+
+// Currently disabled, pending implementation of POSIX message queues
+
+#if 0
+void
+run_mbox_tests(void)
+{
+    int i, cnt;
+    void *item;
+    // Mailbox primitives
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Create mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cnt = cyg_mbox_peek(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Peek [empty] mbox");
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_put(test_mbox_handles[i], (void *)i);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Put [first] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cnt = cyg_mbox_peek(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_put(test_mbox_handles[i], (void *)i);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Put [second] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cnt = cyg_mbox_peek(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_get(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Get [first] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_get(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Get [second] mbox");
+#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_tryput(test_mbox_handles[i], (void *)i);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Tryput [first] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_peek_item(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_tryget(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_peek_item(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Peek item [empty] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        item = cyg_mbox_tryget(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Tryget [empty] mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_waiting_to_get(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Waiting to get mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_waiting_to_put(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Waiting to put mbox");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nmboxes;  i++) {
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_delete(test_mbox_handles[i]);
+        HAL_CLOCK_READ(&mbox_ft[i].end);
+    }
+    show_times(mbox_ft, nmboxes, "Delete mbox");
+
+    run_mbox_circuit_test();
+    end_of_test_group();
+}
+
+//--------------------------------------------------------------------------
+
+void
+run_mbox_circuit_test(void)
+{
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+    int i;
+    // Set my priority lower than any I plan to create
+    cyg_thread_set_priority(cyg_thread_self(), 3);
+    // Set up for full mbox put/get test
+    cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]);
+    cyg_semaphore_init(&synchro, 0);
+    cyg_thread_create(2,              // Priority - just a number
+                      mbox_test,           // entry
+                      0,               // index
+                      thread_name("thread", 0),     // Name
+                      &stacks[0][0],   // Stack
+                      STACK_SIZE,      // Size
+                      &mbox_test_thread_handle,   // Handle
+                      &mbox_test_thread    // Thread data structure
+        );
+    cyg_thread_resume(mbox_test_thread_handle);
+    for (i = 0;  i < nmboxes;  i++) {
+        wait_for_tick(); // Wait until the next clock tick to minimize aberations
+        HAL_CLOCK_READ(&mbox_ft[i].start);
+        cyg_mbox_put(test_mbox_handles[0], (void *)i);
+        cyg_semaphore_wait(&synchro);
+    }
+    cyg_thread_delete(mbox_test_thread_handle);
+    show_times(mbox_ft, nmboxes, "Put/Get mbox");
+#endif
+}
+
+#endif
+
+//--------------------------------------------------------------------------
+
+void
+run_semaphore_tests(void)
+{
+
+    int i;
+    int sem_val;
+
+    // Semaphore primitives
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_init(&test_semaphores[i], 0, 0);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Init semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_post(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Post [0] semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_wait(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_trywait(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        sem_post(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_trywait(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_getvalue(&test_semaphores[i], &sem_val);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Get value of semaphore");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < nsemaphores;  i++) {
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_destroy(&test_semaphores[i]);
+        HAL_CLOCK_READ(&semaphore_ft[i].end);
+    }
+    show_times(semaphore_ft, nsemaphores, "Destroy semaphore");
+
+    run_semaphore_circuit_test();
+    end_of_test_group();
+}
+
+//--------------------------------------------------------------------------
+
+void
+run_semaphore_circuit_test(void)
+{
+
+    int i;
+    struct sched_param schedparam;
+    pthread_attr_t attr;
+    void *retval;
+
+    // Set my priority lower than any I plan to create
+    schedparam.sched_priority = 5;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+
+    // Initiaize thread creation attributes
+
+    pthread_attr_init( &attr );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    // Set up for full semaphore post/wait test
+    sem_init(&test_semaphores[0], 0, 0);
+    sem_init(&synchro, 0, 0);
+
+    pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
+    pthread_attr_setstacksize( &attr, STACK_SIZE );
+    pthread_create( &semaphore_test_thread_handle,
+                    &attr,
+                    semaphore_test,
+                    (void *)0
+        );
+    
+    
+    for (i = 0;  i < nsemaphores;  i++) {
+        wait_for_tick(); // Wait until the next clock tick to minimize aberations
+        HAL_CLOCK_READ(&semaphore_ft[i].start);
+        sem_post(&test_semaphores[0]);
+        sem_wait(&synchro);
+    }
+    pthread_join(semaphore_test_thread_handle, &retval);
+    
+    show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore");
+
+
+}
+
+//--------------------------------------------------------------------------
+
+// Timer callback function
+void
+sigrt0(int signo, siginfo_t *info, void *context)
+{
+    diag_printf("sigrt0 called\n");
+    // empty call back
+}
+
+// Callback used to test determinancy
+static volatile int timer_cnt;
+void
+sigrt1(int signo, siginfo_t *info, void *context)
+{
+    if (timer_cnt == nscheds) return;
+    sched_ft[timer_cnt].start = 0;
+    HAL_CLOCK_READ(&sched_ft[timer_cnt++].end);
+    if (timer_cnt == nscheds) {
+        sem_post(&synchro);
+    }
+}
+
+static sem_t timer_sem;
+
+static void
+sigrt2(int signo, siginfo_t *info, void *context)
+{
+    if (timer_cnt == nscheds) {
+        sem_post(&synchro);
+        sem_post(&timer_sem);        
+    } else {
+        sched_ft[timer_cnt].start = 0;
+        sem_post(&timer_sem);
+    }
+}
+
+// Null thread, used to keep scheduler busy
+void *
+timer_test(void * id)
+{
+    while (true) {
+        cyg_thread_yield();
+        pthread_testcancel();
+    }
+
+    return id;
+}
+
+// Thread that suspends itself at the first opportunity
+void *
+timer_test2(void *id)
+{
+    while (timer_cnt != nscheds) {
+        HAL_CLOCK_READ(&sched_ft[timer_cnt++].end);
+        sem_wait(&timer_sem);
+    }
+    return id;
+}
+
+void
+run_timer_tests(void)
+{
+    int res;
+    int i;
+    struct sigaction sa;
+    struct sigevent sigev;
+    struct itimerspec tp;
+    
+    // Install signal handlers
+    sigemptyset( &sa.sa_mask );
+    sa.sa_flags = SA_SIGINFO;
+
+    sa.sa_sigaction = sigrt0;
+    sigaction( SIGRTMIN, &sa, NULL );
+
+    sa.sa_sigaction = sigrt1;
+    sigaction( SIGRTMIN+1, &sa, NULL );
+
+    sa.sa_sigaction = sigrt2;
+    sigaction( SIGRTMIN+2, &sa, NULL );
+
+    // Set up common bits of sigevent
+
+    sigev.sigev_notify = SIGEV_SIGNAL;
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntimers;  i++) {
+        HAL_CLOCK_READ(&timer_ft[i].start);
+        sigev.sigev_signo = SIGRTMIN;
+        sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
+        res = timer_create( CLOCK_REALTIME, &sigev, &timers[i]);
+        HAL_CLOCK_READ(&timer_ft[i].end);
+        CYG_ASSERT( res == 0 , "timer_create() returned error");
+    }
+    show_times(timer_ft, ntimers, "Create timer");
+
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 0;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 0;
+    for (i = 0;  i < ntimers;  i++) {
+        HAL_CLOCK_READ(&timer_ft[i].start);
+        res = timer_settime( timers[i], 0, &tp, NULL );
+        HAL_CLOCK_READ(&timer_ft[i].end);
+        CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    }
+    show_times(timer_ft, ntimers, "Initialize timer to zero");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    tp.it_value.tv_sec = 1;
+    tp.it_value.tv_nsec = 250000000;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 0;
+    for (i = 0;  i < ntimers;  i++) {
+        HAL_CLOCK_READ(&timer_ft[i].start);
+        res = timer_settime( timers[i], 0, &tp, NULL );
+        HAL_CLOCK_READ(&timer_ft[i].end);
+        CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    }
+    show_times(timer_ft, ntimers, "Initialize timer to 1.25 sec");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 0;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 0;
+    for (i = 0;  i < ntimers;  i++) {
+        HAL_CLOCK_READ(&timer_ft[i].start);
+        res = timer_settime( timers[i], 0, &tp, NULL );
+        HAL_CLOCK_READ(&timer_ft[i].end);
+        CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    }
+    show_times(timer_ft, ntimers, "Disable timer");
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < ntimers;  i++) {
+        HAL_CLOCK_READ(&timer_ft[i].start);
+        res = timer_delete( timers[i] );
+        HAL_CLOCK_READ(&timer_ft[i].end);
+        CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    }
+    show_times(timer_ft, ntimers, "Delete timer");
+    
+    
+
+    sigev.sigev_signo = SIGRTMIN+1;
+    sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
+    res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
+    CYG_ASSERT( res == 0 , "timer_create() returned error");
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 50000000;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 50000000;;
+    timer_cnt = 0;
+    res = timer_settime( timers[0], 0, &tp, NULL );
+    CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    sem_init(&synchro, 0, 0);
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    do
+    { res = sem_wait(&synchro);
+    } while( res == -1 && errno == EINTR );
+    CYG_ASSERT( res == 0 , "sem_wait() returned error");        
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 0;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 0;
+    res = timer_settime( timers[0], 0, &tp, NULL );
+    CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    res = timer_delete( timers[0] );
+    CYG_ASSERT( res == 0 , "timer_delete() returned error");
+    show_times(sched_ft, nscheds, "Timer latency [0 threads]");
+
+
+    
+
+    struct sched_param schedparam;
+    pthread_attr_t attr;
+    void *retval;
+    
+    // Set my priority higher than any I plan to create
+    schedparam.sched_priority = 20;
+    pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam );
+
+    
+    // Initiaize thread creation attributes
+
+    pthread_attr_init( &attr );
+    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
+    pthread_attr_setschedpolicy( &attr, SCHED_RR );
+    schedparam.sched_priority = 10;
+    pthread_attr_setschedparam( &attr, &schedparam );
+    
+    for (i = 0;  i < 2;  i++) {
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        res = pthread_create( &threads[i],
+                        &attr,
+                        timer_test,
+                        (void *)i
+                        );
+        CYG_ASSERT( res == 0 , "pthread_create() returned error");
+    }
+
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+
+    sigev.sigev_signo = SIGRTMIN+1;
+    sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
+    res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
+    CYG_ASSERT( res == 0 , "timer_create() returned error");
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 50000000;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 50000000;;
+    timer_cnt = 0;
+    res = timer_settime( timers[0], 0, &tp, NULL );
+    CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    
+    sem_init(&synchro, 0, 0);
+    do
+    { res = sem_wait(&synchro);
+    } while( res == -1 && errno == EINTR );
+    CYG_ASSERT( res == 0 , "sem_wait() returned error");        
+    res = timer_delete(timers[0]);
+    CYG_ASSERT( res == 0 , "timerdelete() returned error");    
+    show_times(sched_ft, nscheds, "Timer latency [2 threads]");
+    for (i = 0;  i < 2;  i++) {
+        pthread_cancel(threads[i]);
+        pthread_join(threads[i], &retval);
+    }
+
+
+    
+    for (i = 0;  i < ntest_threads;  i++) {
+        pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] );
+        pthread_attr_setstacksize( &attr, STACK_SIZE );
+        res = pthread_create( &threads[i],
+                        &attr,
+                        timer_test,
+                        (void *)i
+                        );
+        CYG_ASSERT( res == 0 , "pthread_create() returned error");
+    }
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    sigev.sigev_signo = SIGRTMIN+1;
+    sigev.sigev_value.sival_ptr = (void*)(&timers[i]);
+    res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
+    CYG_ASSERT( res == 0 , "timer_create() returned error");
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 50000000;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 50000000;;
+    timer_cnt = 0;
+    res = timer_settime( timers[0], 0, &tp, NULL );
+    CYG_ASSERT( res == 0 , "timer_settime() returned error");
+    
+    sem_init(&synchro, 0, 0);
+    do
+    { res = sem_wait(&synchro);
+    } while( res == -1 && errno == EINTR );
+    CYG_ASSERT( res == 0 , "sem_wait() returned error");        
+    res = timer_delete(timers[0]);
+    CYG_ASSERT( res == 0 , "timerdelete() returned error");        
+    show_times(sched_ft, nscheds, "Timer latency [many threads]");
+    for (i = 0;  i < ntest_threads;  i++) {
+        pthread_cancel(threads[i]);
+        pthread_join(threads[i], &retval);
+    }
+
+    sem_init(&synchro, 0, 0);
+    sem_init(&timer_sem, 0, 0);    
+    pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] );
+    pthread_attr_setstacksize( &attr, STACK_SIZE );
+    res = pthread_create( &threads[0],
+                          &attr,
+                          timer_test2,
+                          (void *)0
+        );
+    CYG_ASSERT( res == 0 , "pthread_create() returned error");
+    
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    sigev.sigev_signo = SIGRTMIN+2;
+    sigev.sigev_value.sival_ptr = (void*)(threads[0]);
+    res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]);
+    CYG_ASSERT( res == 0 , "timer_create() returned error");
+    tp.it_value.tv_sec = 0;
+    tp.it_value.tv_nsec = 50000000;
+    tp.it_interval.tv_sec = 0;
+    tp.it_interval.tv_nsec = 50000000;;
+    timer_cnt = 0;
+    res = timer_settime( timers[0], 0, &tp, NULL );
+    CYG_ASSERT( res == 0 , "timer_settime() returned error");
+
+    do
+    { res = sem_wait(&synchro);
+    } while( res == -1 && errno == EINTR );
+    CYG_ASSERT( res == 0 , "sem_wait() returned error");        
+    res = timer_delete(timers[0]);
+    CYG_ASSERT( res == 0 , "timerdelete() returned error");        
+    show_times(sched_ft, nscheds, "Timer -> thread post latency");
+    sem_post(&timer_sem);
+//    pthread_cancel(threads[0]);
+    pthread_join(threads[0], &retval);
+
+
+    end_of_test_group();
+}
+
+
+//--------------------------------------------------------------------------
+
+void 
+run_all_tests()
+{
+    int i;
+    cyg_uint32 tv[nsamples], tv0, tv1;
+//    cyg_uint32 min_stack, max_stack, total_stack, actual_stack, j;
+    cyg_tick_count_t ticks, tick0, tick1;
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+    cyg_uint32 lock_ave, lock_max;
+#endif
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+    cyg_int32 clock_ave;
+#endif
+
+    disable_clock_latency_measurement();
+
+//    cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] );
+    cyg_test_dump_interrupt_stack_stats( "Startup" );
+    cyg_test_dump_idlethread_stack_stats( "Startup" );
+    cyg_test_clear_interrupt_stack();
+
+    diag_printf("\neCos Kernel Timings\n");
+    diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n");
+#ifdef STATS_WITHOUT_FIRST_SAMPLE
+    diag_printf("       second line of results have first sample removed\n");
+#endif
+
+    cyg_thread_delay(2);  // Make sure the clock is actually running
+
+    ns_per_system_clock = 1000000/rtc_resolution[1];
+
+    for (i = 0;  i < nsamples;  i++) {
+        HAL_CLOCK_READ(&tv[i]);
+    }
+    tv0 = 0;
+    for (i = 1;  i < nsamples;  i++) {
+        tv0 += tv[i] - tv[i-1];
+    }
+    end_of_test_group();
+    
+    overhead = tv0 / (nsamples-1);
+    diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead);
+    diag_printf("... this value will be factored out of all other measurements\n");
+
+    // Try and measure how long the clock interrupt handling takes
+    for (i = 0;  i < nsamples;  i++) {
+        tick0 = cyg_current_time();
+        while (true) {
+            tick1 = cyg_current_time();
+            if (tick0 != tick1) break;
+        }
+        HAL_CLOCK_READ(&tv[i]);
+    }
+    tv1 = 0;
+    for (i = 0;  i < nsamples;  i++) {
+        tv1 += tv[i] * 1000;
+    }
+    tv1 = tv1 / nsamples;
+    tv1 -= overhead;  // Adjust out the cost of getting the timer value
+    diag_printf("Clock interrupt took");
+    show_ticks_in_us(tv1);
+    diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000);
+    enable_clock_latency_measurement();
+
+    ticks = cyg_current_time();
+
+    show_test_parameters();
+    show_times_hdr();
+
+    reset_clock_latency_measurement();
+
+    run_thread_tests();
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+    run_mutex_tests();
+//    run_mbox_tests();
+#endif
+    run_semaphore_tests();
+    run_timer_tests();
+
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+    Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max);
+    diag_printf("\nMax lock:");
+    show_ticks_in_us(lock_max);
+    diag_printf(", Ave lock:");
+    show_ticks_in_us(lock_ave);
+    diag_printf("\n");
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+    // Display latency figures in same format as all other numbers
+    disable_clock_latency_measurement();
+    clock_ave = (total_clock_latency*1000) / total_clock_interrupts;
+    show_ticks_in_us(clock_ave);
+    show_ticks_in_us(min_clock_latency*1000);
+    show_ticks_in_us(max_clock_latency*1000);
+    show_ticks_in_us(0);
+    diag_printf("            Clock/interrupt latency\n\n");
+    enable_clock_latency_measurement();    
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
+    disable_clock_latency_measurement();    
+    clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls;
+    show_ticks_in_us(clock_ave);
+    show_ticks_in_us(min_clock_dsr_latency*1000);
+    show_ticks_in_us(max_clock_dsr_latency*1000);
+    show_ticks_in_us(0);
+    diag_printf("            Clock DSR latency\n\n");
+    enable_clock_latency_measurement();
+#endif
+
+#if 0    
+    disable_clock_latency_measurement();
+    min_stack = STACK_SIZE;
+    max_stack = 0;
+    total_stack = 0;
+    for (i = 0;  i < (int)NTEST_THREADS;  i++) {
+        for (j = 0;  j < STACK_SIZE;  j++) {
+            if (stacks[i][j]) break;
+        }
+        actual_stack = STACK_SIZE-j;
+        if (actual_stack < min_stack) min_stack = actual_stack;
+        if (actual_stack > max_stack) max_stack = actual_stack;
+        total_stack += actual_stack;
+    }
+    for (j = 0;  j < STACKSIZE;  j++) {
+        if (((char *)stack[0])[j]) break;
+    }
+    diag_printf("%5d   %5d   %5d  (main stack: %5d)  Thread stack used (%d total)\n", 
+                total_stack/NTEST_THREADS, min_stack, max_stack, 
+                STACKSIZE - j, STACK_SIZE);
+#endif
+    
+//    cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] );
+    cyg_test_dump_interrupt_stack_stats( "All done" );
+    cyg_test_dump_idlethread_stack_stats( "All done" );
+
+    enable_clock_latency_measurement();
+
+    ticks = cyg_current_time();
+    diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000));
+
+    CYG_TEST_PASS_FINISH("Basic timing OK");
+}
+
+int main( int argc, char **argv )
+{
+    CYG_TEST_INIT();
+
+    if (cyg_test_is_simulator) {
+        nsamples = NSAMPLES_SIM;
+        ntest_threads = NTEST_THREADS_SIM;
+        nthread_switches = NTHREAD_SWITCHES_SIM;
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+        nmutexes = NMUTEXES_SIM;
+#endif
+        nmboxes = NMBOXES_SIM;
+        nsemaphores = NSEMAPHORES_SIM;
+        nscheds = NSCHEDS_SIM;
+        ntimers = NTIMERS_SIM;  
+    } else {
+        nsamples = NSAMPLES;
+        ntest_threads = NTEST_THREADS;
+        nthread_switches = NTHREAD_SWITCHES;
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+        nmutexes = NMUTEXES; 
+#endif
+        nmboxes = NMBOXES;
+        nsemaphores = NSEMAPHORES;
+        nscheds = NSCHEDS;
+        ntimers = NTIMERS;
+    }
+
+    // Sanity
+#ifdef WORKHORSE_TEST
+    ntest_threads = max(512, ntest_threads);
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+    nmutexes = max(1024, nmutexes);
+#endif
+    nsemaphores = max(1024, nsemaphores);
+    nmboxes = max(1024, nmboxes);
+    ncounters = max(1024, ncounters);
+    ntimers = max(1024, ntimers);
+#else
+    ntest_threads = max(64, ntest_threads);
+#ifdef CYGPKG_POSIX_PTHREAD_MUTEX
+    nmutexes = max(32, nmutexes);
+#endif
+    nsemaphores = max(32, nsemaphores);
+    nmboxes = max(32, nmboxes);
+    ntimers = max(32, ntimers);
+#endif
+
+    run_all_tests();
+   
+}
+
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+// EOF tm_posix.cxx
diff --git a/packages/net/.cvsignore b/packages/net/.cvsignore
new file mode 100644 (file)
index 0000000..fc538ed
--- /dev/null
@@ -0,0 +1 @@
+openssl
\ No newline at end of file
diff --git a/packages/net/athttpd/v2_0/ChangeLog b/packages/net/athttpd/v2_0/ChangeLog
new file mode 100644 (file)
index 0000000..d3c7d08
--- /dev/null
@@ -0,0 +1,241 @@
+2008-06-18  Oyvind Harboe  <oyvind.harboe@zylin.com>
+
+       * src/jim-aio.c (JimAioHandlerCommand): GCC 4.3.1 pointed out a
+       buffer overrun.
+
+2008-06-17 Anthony Tonizzo <atonizzo@gmail.com>
+
+       Jumbo patch containing many individual patches from a number of
+       different contributors on different days. The ChangeLog entries
+       for all these individual patches are:
+       
+        2007-12-02  Anthony Tonizzo <atonizzo@gmail.com>
+
+       * src/socket.c src/httpd.c: Corrected a bug in
+       cyg_httpd_write_chunked(): Now the CRLF that terminates a chunk is
+       added by the function and not expected to be there already in the
+       data supplied by the user. Modified the function
+       cyg_httpd_end_chunked() so that the flag
+       CYG_HTTPD_MODE_TRANSFER_CHUNKED is always cleared after it
+       terminates. The cyg_httpd_process_request() now loops as many
+       times as the number of full requests received.  Renamed header_end
+       to request_end to better reflect its real use, and the fact that
+       the former name was misleading for POST requests (Danny
+       Sade). Changed the function that collects a request: Now the
+       remaining part of an incomplete request is copied back to the
+       beginning of the buffer. This avoids that multiple split headers
+       might creep towards the end of the buffer.
+
+        2007-11-28  Rene' Nielsen <rbn@vitesse.com> and 
+                   Anthony Tonizzo <atonizzo@gmail.com>
+
+       * doc/athttpd.sgml: Included Digest (MD5) authentication as fully
+       supported.
+       * cdl/httpd.cdl: Updated the cdl to reflect the fact that MD5
+       authentication is now a fully tested feature, at least on some
+       clients (Thanks to Tad for testing this!)
+       * src/httpd.c: Added the initialization of the global variable
+       cyg_httpd_md5_response. This corrects a security hole that could
+       allow unauthenticated browsers to access pages that require
+       authentication. This required a minor change (switch of variables
+       used) in the authentication code. Added code to avoid a buffer
+       overflow during the parsing of headers for authenticated
+       pages. Clear the CYG_HTTPD_MODE_SEND_HEADER_ONLY at the beginning
+       of any request.
+       * src/auth.c: Removed dead code and made static a bunch of
+       functions and variables.
+       * src/auth.h: The AUTH_STORAGE_BUFFER_LENGTH value is now split
+       into two numbers, one that gives the maximum length of the login
+       phrase and one for the password.
+       * src/socket.c: Added a NULL terminator after each header packet
+       that is received. Now the strstr() is guaranteed to find
+       terminated string.
+
+        2007-11-27  Tad Artis <ecos@ds3switch.com>
+
+       * src/auth.c: Modified the cyg_httpd_digest_data() and
+       cyg_httpd_digest_skip() functions to support IE7. A careful read
+       of the augmented BNF in RFC2616 indicates that spaces within the
+       elements of the authentication header are optional. The original
+       atHTTPD code incorrectly relied on a space after the comma. Moved
+       the authentication check inside cyg_httpd_process_method() so that
+       each request, regardless of the type, will have to go through
+       authentication.
+
+        2007-11-26  Tad Artis <ecos@ds3switch.com> and 
+                   Anthony Tonizzo <atonizzo@gmail.com>
+
+       * src/forms.c: Checked for a null terminator inside
+       cyg_httpd_store_form_variable, so that we do not scan past the end
+       of the packet. Check the form variables for both length and
+       content, to avoid false positives. Modified cyg_httpd_from_hex()
+       to return -1 in case of error.
+       * src/httpd.c: Corrected the strings sent back by the server to
+       challenge the client to an MD5 authentication. Adds a couple of
+       commas to separate the items in the string.
+       * src/http.h:
+       * src/socket.h: Corrected a number of indexes where
+       CYGNUM_FILEIO_NFILE was used instead of the correct
+       CYGPKG_NET_MAXSOCKETS.
+
+2008-03-04  Danny Sade  <danny@channelot.com>
+
+       * src/socket.c: put NULL at the end of inbuff on each iteration,
+       preventing strstr from looking at old data beyond inbuffer_len
+
+2007-11-12  Oyvind Harboe  <oyvind.harboe@zylin.com>
+2007-11-12  Jonathan Larmour  <jifl@eCosCentric.com>
+
+       * doc/athttpd.sgml: added an example of a tcl script.
+       * src/http.c, forms.c: serve cgi requests before file system requests,
+       that way it isn't possible to download the actual cgi/.o script and
+       cgi works even if the http root directory is above the cgi directory.
+       * src/http.c: if only tcl cgi is enabled, cgi requests are now
+       forwarded to tcl
+       * include/jim.h: include file order fix; now compiles again.
+       * doc/athttpd.sgml: Fixed typos in doc. Return value from handler is
+       not used, recommend returning 0 in doc.
+
+2006-12-03  Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * cdl/httpd.cdl: Corrected a CDL error in the requirements of
+       CYGOPT_NET_ATHTTPD_USE_FS
+
+2006-11-27  Jonathan Larmour  <jifl@eCosCentric.com>
+
+       * cdl/httpd.cdl: Improve CDL dependencies.
+
+2006-11-08  Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * doc/athttpd.sgml: Updated to describe lasted changes and corrected
+       minor typos.
+       * src/http.c: Check for "Content-Type" header. This is needed if we
+       want to support parsing form variables in POST requests.
+       * src/jim.c: Updated with latest release from Jim CVS.
+       * src/cgi.c: streamlined cyg_httpd_exec_cgi_tcl(), now uses the 'source'
+       command of tcl to execute a tcl script.
+       * src/forms.c: Modified cyg_handle_method_POST so that the variables in the
+       payload are scanned only if the request has a Content-Type 
+       of 'application/x-www-form-urlencoded'
+       * src/jim-aio.c: Added to package. Now tcl has IO functions to access a
+       file system.
+       * include/httpd.h: Added a new mode, CYG_HTTPD_MODE_FORM_DATA which is set
+       when a POST request has a Content-Type of 
+       'application/x-www-form-urlencoded'
+           
+2006-10-16  Lars Povlsen  <lpovlsen@vitesse.com> and Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * cdl/httpd.cdl: add CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS. Default
+       is set to CLOSE, so it is backward compatible with 
+       previous versions of the browser.
+       * src/socket.c: cyg_httpd_process_request() uses a loop to collect at least
+       one full frame (til a header terminator is found), 
+       cyg_httpd_start_chunked() only close if configured to do so.
+       * src/httpd.c: Overhaul of cyg_httpd_send_error to avoid the use of
+       inbuffer as temporary storage (conflicts with pipelined frames),
+       removed the option to send a page after calling a C language
+       handler
+       * include/httpd.h: Added a new mode, CYG_HTTPD_MODE_NO_CACHE
+           
+2006-10-12  Lars Povlsen  <lpovlsen@vitesse.com> and Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * cdl/httpd.cdl: add CYGNUM_ATHTTPD_SERVER_MAX_POST to limit POST'ed data
+       * include/http.h: Added header_end, post_data fields to httpstate,
+       Added "302 Found" for POST handler redirect (CYG_HTTPD_STATUS_MOVED_TEMPORARILY)
+       * src/forms.c: Fixed variable decoding, fixed large POST processing
+       * src/http.c: Fixed some debug ouptuts, cleanup after POST processing, 
+       overhaul of the pipelined requests code which can now
+       handle multiple requests per frame.
+       * src/socket.c: Removed assert for socket write failure, Accumulating receiving
+       of requests (Browsers (Firefox) may pass partial headers in separate 
+       fragments). Fixed some diagnostics output.
+
+2006-07-19  Anthony Tonizzo  <atonizzo@gmail.com> and Sergei Gavrikov  <w3sg@softhome.net>
+
+       * cdl/httpd.cdl: 
+       * doc/athttpd.sgml: Corrected some typos and rectified some omissions.
+       * include/jim.h:    Added an inline to Jim_InitExtension()
+       * src/cgi.c:        used malloc() instead of cyg_ldr_malloc();
+       * src/forms.c:      Added a #define to be able tio use the TCL scripting
+       without OBJLOADER
+       * src/http.c:       
+       * src/socket.c:     Lots of typos stamped out, and some better comments too.
+                            
+2006-07-19  Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * src/socket.c: Corrected a typo that generated an assertion.
+       Modified slightly the source of cyg_httpd_write and cyg_httpd_writev
+       to make the code more consistent as to when assertions are thrown.
+
+2006-07-19  Sergei Gavrikov  <w3sg@softhome.net>
+
+       * doc/athttpd.sgml: jade doesn't allow underscores in
+       id attributes, so fix.
+
+2006-07-18  Jonathan Larmour  <jifl@eCosCentric.com>
+
+       * cdl/httpd.cdl: Add -D __ECOS in compiler flags.
+       Change include_dir to cyg/athttpd.
+       Rename all CDL options from *_HTTPD_* to *_ATHTTPD_*.
+       * All files: Rename cyg/httpd include directory to cyg/athttpd.
+       Rename all CDL options from *_HTTPD_* to *_ATHTTPD_*.
+       * doc/athttpd.sgml: Document MD5 algorithm licensing.
+       * src/socket.c: Remove unused SNTP include.
+
+2006-06-13  Anthony Tonizzo  <atonizzo@gmail.com>
+
+       * cdl/httpd.cdl: 
+       * doc/athttpd.sgml: 
+       * doc/mime_types.txt: 
+       * include/auth.h: 
+       * include/cgi.h: 
+       * include/digcalc.h: 
+       * include/forms.h: 
+       * include/global.h: 
+       * include/handler.h: 
+       * include/http.h: 
+       * include/jim.h: 
+       * include/md5.h: 
+       * include/socket.h: 
+       * src/auth.c: 
+       * src/cgi.c: 
+       * src/forms.c: 
+       * src/handler.c: 
+       * src/http.c: 
+       * src/jim.c: 
+       * src/md5c.c: 
+       * src/socket.c: 
+       Created ATHTTPD package.
+       
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2005, 2006 eCosCentric Ltd.
+//
+// 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####
+//===========================================================================
diff --git a/packages/net/athttpd/v2_0/cdl/httpd.cdl b/packages/net/athttpd/v2_0/cdl/httpd.cdl
new file mode 100644 (file)
index 0000000..2813d1f
--- /dev/null
@@ -0,0 +1,353 @@
+# ====================================================================
+#
+#      httpd.cdl
+#
+#      HTTP server configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2005 eCosCentric Ltd.
+##
+## 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):      Anthony Tonizzo (atonizzo@gmail.com)
+# Contributors:   Lars Povlsen    (lpovlsen@vitesse.com)
+# Date:           2006-06-09
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_ATHTTPD {
+    display       "Another Tiny HTTP server"
+    description   "This package provides a small footprint web server for eCos
+                   with configurable features."
+    include_dir   cyg/athttpd
+    include_files auth.h digcalc.h forms.h global.h handler.h http.h md5.h socket.h cgi.h jim.h
+    compile       forms.c handler.c http.c socket.c cgi.c
+    requires      CYGPKG_NET
+    requires      CYGPKG_NET_STACK_INET
+    requires      !CYGPKG_HTTPD
+    requires      CYGINT_ISO_STDIO_STREAMS
+    requires      CYGINT_ISO_STDIO_FILEACCESS
+    requires      CYGINT_ISO_STDIO_FORMATTED_IO
+    requires      CYGINT_ISO_STRING_MEMFUNCS
+    requires      CYGINT_ISO_STRING_STRFUNCS
+    requires      CYGINT_ISO_STRING_BSD_FUNCS
+    requires      CYGINT_ISO_C_CLOCK_FUNCS
+    requires      CYGINT_ISO_MALLOC
+    requires      CYGINT_ISO_CTYPE
+
+# ====================================================================
+   
+    cdl_component CYGPKG_NET_ATHTTPD_THREADOPT {
+        display "Thread settings"
+        flavor  none
+        no_define
+        description   "Options to change certain thread values."
+
+      cdl_option CYGNUM_NET_ATHTTPD_THREADOPT_PRIORITY {
+          display "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_NET_ATHTTPD_THREADOPT_STACKSIZE {
+          display "Thread stack size"
+          flavor data
+          default_value 4096
+          description "This is the amount of extra stack to be
+                       allocated for the HTTPD thread. This value is
+                       added to CYGNUM_HAL_STACK_SIZE_MINIMUM to
+                       determine the final size of the stack for the
+                       server."  
+      } 
+    }
+
+    cdl_component CYGOPT_NET_ATHTTPD_SERVEROPT {
+        display "Server settings"
+        flavor  none
+        no_define
+        description   "Options to change certain server options."
+
+      cdl_option CYGNUM_NET_ATHTTPD_SERVEROPT_PORT {
+          display "Server Port"
+          flavor data
+          default_value 80
+          description "This is the port on which the server will be listening
+                      for requests. Unless overridden in the request by the 
+                      client, the well known port for HTTP is 80."
+      }
+
+      cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID {
+          display "Server ID string"
+          flavor data
+          default_value {"\"eCos Embedded Web Server\""}
+          description "This is the string sent out in the 'Server:' 
+                       header line."
+      }
+      
+      cdl_option CYGNUM_ATHTTPD_SERVER_BUFFER_SIZE {
+          display "IO buffer size"
+          flavor data
+          default_value 2048
+          description "This option defines the size of the buffers used to 
+                       receive and transmit transmit data to and from the 
+                       TCP/IP stack."
+      }
+
+      cdl_option CYGNUM_ATHTTPD_SERVER_MAX_POST {
+          display "Maximum data received upon POST"
+          flavor data
+          default_value 2048
+          description "This option defines the size of maximum amount of data 
+                       the web server will accept from POST'ed forms."
+      }
+
+      cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR {
+          display "HTTPD root directory"
+          flavor data
+          default_value {"\"/\""}
+          description "This is the absolute path in the eCos file
+                       system to the HTML documents, including cgi-bin
+                       files and error files and it is generally where
+                       the web server will look for the index
+                       file. Include a trailing slash."
+      }
+      
+      cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR {
+          display "cgi-bin directory"
+          active_if    { 0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER || 
+                         0 != CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL }
+          flavor data
+          default_value {"\"cgi-bin/\""}
+          description "This is the path, relative to
+                       CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR, where the
+                       cgi-bin files are stored. Based on the
+                       extension of the cgi-bin file requested, the
+                       appropriate interpreter will be used. Include a
+                       trailing slash."
+      }
+      
+      cdl_option CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR {
+          display "Error files directory"
+          flavor data
+          default_value {"\"errors/\""}
+          description "This is the path, relative to the
+                       CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR, that
+                       contains the user-defined files that are sent
+                       out by the server in case of error. The files
+                       are named error_XXX.html where XXX is the 3
+                       digit HTML code.  For example, for a 404 error
+                       the server file will be named
+                       error_404.html. Upon a 404 error, the server
+                       will check the existence of such a file in this
+                       directory and if found, it will send it
+                       out. Missing that file, a standard simple
+                       message will be sent instead. Include a
+                       trailing slash."
+      }
+
+      cdl_option CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE {
+          display "Default MIME type"
+          flavor data
+          default_value {"\"text/plain\""}
+          description "When accessing internal resources or a file
+                       system, the MIME type is determined by first
+                       finding the extension of the file itself and
+                       then by looking up the extension in the MIME
+                       table. In case no extension is found the user
+                       can define the default MIME type to use. Notice
+                       that this is the full MIME type and not the
+                       extension.  A list of standard MIME types
+                       sorted by extension can be found in the
+                       current/doc directory" 
+      }
+      
+      cdl_option CYGDAT_NET_ATHTTPD_ALTERNATE_HOME {
+          display "User defined Home Page"
+          flavor booldata
+          default_value {"\"/index.html\""}
+          description "This file name defines the name of a custom index file 
+                       and is used in case none of the default index files are 
+                       found in a directory. Notice that this file name is
+                       only appended to GET requests for \"/\""
+      }
+    }  
+
+    cdl_option CYGOPT_NET_ATHTTPD_USE_FS {
+        display       "Support for file system access"
+        flavor        bool
+        default_value 1
+        active_if     CYGPKG_IO_FILEIO
+        description   "
+            This option enables the use of a file system to access the pages
+             to be served. It is the responsibility of the user to properly
+             mount the file system(s) required by the web server. If this
+             option is not selected each URL requested must be serviced using
+             either c language callbacks or internal resources." 
+    }
+
+    cdl_option CYGOPT_NET_ATHTTPD_USE_AUTH {
+        display       "Support for basic and digest authentication"
+        flavor        bool
+        default_value 0
+        description   "
+            This option enables the use basic authentication in web pages.
+            Not all clients have been tested." 
+       compile md5c.c
+       compile auth.c
+    }
+
+    cdl_option CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS {
+        display       "Close connections used for chunked transfers"
+        flavor        bool
+        default_value 1
+        description   "
+            This option causes connections used for chunked transfer
+            to be closed after use. Persisting the connection will use
+            less network resources and will improve latency, but may
+            do so at the risk of compatibility with older browsers."
+    }
+
+    cdl_option CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME {
+        display          "Maximum lifetime of a document in seconds"
+        flavor           data
+        default_value    0
+        description      "
+            This options causes documents to 'expire' after a set number
+            of seconds. If certain pages are updated frequently, it might be a
+            good idea to assign them an expitation time in seconds. If the
+            client needs to reload a page that has expired, it will request
+            it again, otherwise it will use the copy in the cache. A value
+            of 0 means that this option is disabled. Any other value
+            represents the number of seconds (after the last modification to
+            the document) after which the page becomes stale. This option
+            applies to all the pages (including those that reside in ROM
+            and thus, by definition, won't change) and thus is it preferable
+            to use the CYG_HTTPD_MODE_NO_CACHE mode for pages that need to be
+            refreshed frequently."
+    }
+
+    cdl_option CYGOPT_NET_ATHTTPD_USE_DIRLIST {
+        display       "Support for directory listing"
+        flavor        bool
+        default_value 0
+        active_if     CYGPKG_IO_FILEIO
+        active_if     CYGOPT_NET_ATHTTPD_USE_FS
+        description   "
+            When a client issues a request that ends in '/' the server will
+            try to locate anyone of a number of index files. Failing to find
+            one, it will list the directory contents."
+    }
+
+    cdl_component CYGOPT_NET_ATHTTPD_CGIBIN {
+        display "Supported CGI Types"
+        flavor  none
+        no_define
+        description   "Options to select which CGI types are supported."
+
+      cdl_option CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER {
+          display       "Support cgi via the OBJLOADER package"
+          flavor        bool
+          default_value 0
+          active_if     CYGPKG_OBJLOADER
+          description   "This option enables the use of the object loader 
+                         package as a means of providing on-demand loading and 
+                         execution of code, thus providing a simple cgi
+                         capability that does not involve scripting." 
+      }
+
+      cdl_option CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL {
+          display       "Support cgi via the a simple tcl interpreter (jim)"
+          flavor        bool
+          default_value 0
+          description   "This option enables the use of a small tcl
+                         interpreter as a means of providing a simple cgi
+                         capability. Checking this option increases 
+                         considerably the size of the executable." 
+          compile       jim.c jim-aio.c
+          define        JIM_ANSIC
+          define        JIM_STATICEXT
+      }
+    }  
+
+    cdl_option CYGOPT_NET_ATHTTPD_DEBUG_LEVEL {
+        display          "Verbosity of debug output"
+        flavor           data
+        legal_values     0 1 2
+        default_value    0
+        description      "This option allows controls over the verbosity of
+                         the debug output. 1 mostly reports opening and
+                         closing of socket descriptors, 2 is very
+                         verbose, including the name of all files sent
+                         out, including internal resources."
+    }
+    cdl_component CYGPKG_ATHTTPD_OPTIONS {
+        display "AT HTTP server build options"
+        flavor  none
+        no_define
+
+        cdl_option CYGPKG_ATHTTPD_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_ATHTTPD_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the HTTP server package. These flags are removed from
+                the set of global flags if present."
+        }
+    }
+}
+
+# ====================================================================
+# EOF httpd.cdl
diff --git a/packages/net/athttpd/v2_0/doc/athttpd.sgml b/packages/net/athttpd/v2_0/doc/athttpd.sgml
new file mode 100644 (file)
index 0000000..c14b333
--- /dev/null
@@ -0,0 +1,640 @@
+<!-- DOCTYPE part  PUBLIC "-//OASIS//DTD DocBook V3.1//EN" -->
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     athttpd.sgml                                                -->
+<!--                                                                 -->
+<!--     Another Tiny HTTPD Server for eCos                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2003, 2004, 2007 eCosCentric Ltd.                       -->
+<!-- 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/)                            -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+
+<part id="athttpd">
+<title>Another Tiny HTTP Server for <productname>eCos</productname></title>
+
+<partintro>
+<para>
+This package provides an extensible, small footprint, full featured HTTP
+server for <productname>eCos</productname>. Many of these features can be
+disabled via the configuration tool, thus reducing the footprint of the server.
+The server has been written for the FreeBSD network stack. 
+</para>
+</partintro>
+
+<chapter id="net-athttpd">
+<title>The ATHTTP Server</title>
+<sect1 id="athttpd-features">
+<title>Features</title>
+<para>This ATHTTP implementation provides the following features:</para>
+<itemizedlist>
+  <listitem><para>GET, POST and HEAD Methods</para></listitem>
+  <listitem><para>File system Access</para></listitem>
+  <listitem><para>Callbacks to C functions</para></listitem>
+  <listitem><para>MIME type support</para></listitem>
+  <listitem><para>CGI mechanism through the OBJLOADER package or through a
+                  simple tcl interpreter</para></listitem>
+  <listitem><para>Basic and Digest (MD5) Authentication</para></listitem>
+  <listitem><para>Directory Listing</para></listitem>
+  <listitem><para>Extendable Internal Resources</para></listitem>
+</itemizedlist>
+
+<para>
+Ecos tables are used extensively throught the server to provide a high degree
+of customization.</para>
+</sect1>
+
+<sect1 id="athttpd-using">
+<title>Starting the server</title>
+<para>
+In order to start the web server, the user needs to call the function:</para>
+
+<programlisting width=72>
+cyg_httpd_start();
+</programlisting>
+
+<para>in the application code. The server initialization code spawns a new 
+thread which calls <command>init_all_network_interfaces()</command> to 
+initialize the TCP/IP stack and then starts the deamon. The function is safe
+to call multiple times.
+</para>
+</sect1>
+
+<sect1 id="athttpd-mime-types">
+<title>MIME types</title>
+<para>
+The server has an internal table with all the recognized mime types. Each time
+a file or an internal resource is sent out by the server, its extension is 
+searched in this table and if a match is found, the associated MIME type is
+then sent out in the header. 
+
+The server already provides entries for the following standard file extensions:
+
+'html', 'htm', 'gif', 'jpg', 'css', 'js', 'png'
+
+and the user is responsible for adding any further entry. The syntax for 
+adding an entry is the following:</para>
+
+<para><programlisting width=72>
+CYG_HTTPD_MIME_TABLE_ENTRY(entry_label, extension_string, mime_tipe_sting);
+
+entry table      : an identifier unique to this entry
+extension string : a string containing the extension for this entry
+type_string      : the mime string. The strings for many more mime types 
+                   is included in a file in the "doc" directory.
+</programlisting></para>
+
+<para>
+The following is an example of how to add the Adobe Portable Document Format
+<command>pdf</command> MIME type to the table:</para>
+
+<para><programlisting width=72>
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_pdf_entry, "pdf", "application/pdf");
+</programlisting></para>
+
+<sect2 id="athttpd-mime-types-chunked">
+<title>MIME Types for Chunked Frames</title>
+<para>
+For chunked frames, which are generally used inside c language callbacks, there
+is no file name to match an extension to, and thus the extension to be used
+must be passed in the <command>cyg_httpd_start_chunked()</command> call. The
+server will then scan the MIME table to find a MIME type to match the extension.
+
+For example, to start a chunked transfer of an <command>html</command> file, 
+the following call is used:</para>
+
+<para><programlisting width=72>
+cyg_httpd_start_chunked("html");
+</programlisting></para>
+
+<para>
+In any event, it is the responsibility of the user to make sure that a match to
+all used extensions is found in the table search. Failing this, 
+the default MIME type specified in the CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE
+string is returned.</para>
+</sect2>
+</sect1>
+
+<sect1 id="athttpd-callback">
+<title>C language callback functions</title>
+<para>
+The server allows the association of particular URLs to C language callback 
+functions. eCos tables are used to define the association between a URL and its
+corresponding callback. The syntax of the macro to add callback entries to 
+the table is:
+</para>
+
+<para><programlisting width=72>
+CYG_HTTPD_HANDLER_TABLE_ENTRY(entry_label, url_string, callback);
+
+entry table      : an identifier unique to this entry.
+url_string       : a string with the extension url that will be appended to the
+                   default directory.
+callback         : a function with a prototype:
+                   cyg_int32 callback_function(CYG_HTTPD_STATE*); 
+                   Return value is ignored - just return 0.
+</programlisting></para>
+
+<para>
+<command>CYG_HTTPD_STATE*</command> is a pointer to a structure that
+contains, among others, a buffer (outbuffer) that can be used to send data
+out. The definitions of the structure is in http.h.</para>
+
+<para>
+The following is an example of how to add a callback to a function myForm()
+whenever the URL /myform.cgi is requested:
+</para>
+
+<programlisting width=72>
+CYG_HTTPD_HANDLER_TABLE_ENTRY(hal_cb_entry, "/myform.cgi", myForm);
+</programlisting>
+
+<para>
+and somewhere in the source tree there is a function:</para>
+
+<programlisting>
+cyg_int32 myForm(CYG_HTTPD_STATE* p)
+{
+   cyg_httpd_start_chunked("html");
+   strcpy(p->outbuffer, "eCos Web Server");
+   cyg_httpd_write_chunked(p->outbuffer, strlen(p->outbuffer))
+   cyg_httpd_end_chunked();
+}  
+</programlisting>
+
+<para>This function also shows the correct method of using the chunked frames
+API inside a c language callback and also shows the use of outbuffer to
+collect data to send out.</para>
+
+<para>Chunked frames are useful when the size of the frame is not known upfront. 
+In this case it possible to send a response in chunks of various sizes, and
+terminate it with a null chunk (See RFC 2616 for details). To use chunked 
+frames, the <command>cyg_httpd_start_chunked()</command> function is used. 
+The prototype is the following:</para>
+
+<programlisting>
+ssize_t cyg_httpd_start_chunked(char *);
+</programlisting>
+
+<para>The only parameter is the <command>extension</command> to use in the 
+search for the MIME type. For most files this will be "html" or "htm" and
+it will be searched in the MIME table for an approriate MIME type that will
+be sent along in the header. The function returns the number of bytes sent
+out.</para>
+
+<para>The chunked frame must be terminated by a call to 
+<command>cyg_httpd_end_chunked()</command>:</para>
+
+<programlisting>
+void cyg_httpd_end_chunked()(void);
+</programlisting>
+
+<para>In between these two calls, the user can call the function
+<command>cyg_httpd_write_chunked()</command> to send out data any number of
+times. It is important that <command>cyg_httpd_write_chunked()</command> be
+the only function used to send data out for chunked frames. This
+guarantees that proper formatting of the response is respected.
+The prototype for the function is:</para>
+
+<programlisting>
+ssize_t cyg_httpd_write_chunked(char* p, int len);
+</programlisting>
+
+<para>The 'char*' points to the data to send out, the 'int' is the length of the
+data to send.</para>
+
+<para>In the case in which the size of the data is known upfront, the
+callback can instead create the header with a call to
+<command>cyg_httpd_create_std_header()</command> with the following
+prototype:</para>
+
+<programlisting>
+void cyg_httpd_create_std_header(char *ext, int len);
+
+extension   : the extension used in the search of the MIME type
+len         : length of the data to send out
+</programlisting>
+
+<para>and use
+<command>cyg_httpd_write()</command> to send data out to the client. The
+ prototype of <command>cyg_httpd_write()</command> is the same as 
+<command>cyg_httpd_write_chunked()</command></para></sect1>
+
+<sect1 id="athttpd-cgi">
+<title>CGI</title>
+<para>
+The web server allows writing of pseudo-CGI programs. This is helpful in order
+to modify the functionality of the server without having to recompile it and
+reflash it.</para>
+
+<para>One way to implement CGI is, of course, the C language callback mechanism
+described above: This assumes, of course, that all the callbacks are written
+by compile time and cannot be modified later on. Another way to perform the
+same functionality is the use of a library in the form of an object file. 
+These object files reside in the file system and are loaded, executed and 
+unloaded on demand.</para>
+
+<para>Yet a third way is the use of a scripting language. Since full fledged
+implementation of the most popular scripting languages such as Python or Perl
+are too large for most embedded systems, a slim down implementation of tcl
+was chosen for this server. Most of the tcl functionality is still there,
+and makes writing cgi a lot easier.</para>
+
+<para>In order to limit the footprint of the operating system support for both
+the objloader and the tcl script for dealing with cgi files can be 
+independently selected out. Tcl support in particular increases the memory
+requirements considerably.
+</para>
+
+<sect2 id="athttpd-cgi-objloader">
+<title>CGI via objloader</title>
+<para>
+In order to use the cgi mechanism the CYGPKG_OBJLOADER must be included
+when building the operating system. This will enable the proper option in the
+configuration tool and if selected, the necessary code will be compiled
+in the eCos kernel. The user will then have to compile the necessary libraries
+and place them in the file system under a directory defined by 
+CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR.
+When a request is made, the web server checks if the root directory of the 
+requested URL is inside the CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR directory.
+If so, the server assumes that the user requested a cgi file and looks into the
+directory to see if a library by the same name is present, and if so load it
+and tries to execute a function inside the library with the following prototype:
+</para>
+
+<programlisting width=72>void exec_cgi(CYG_HTTPD_STATE *)
+</programlisting>
+
+<para>
+The pointer <command>CYG_HTTPD_STATE*</command> gives access to the socket 
+data: The user will use this pointer to access the 'outbuffer' and use it to
+copy data to send data out.
+</para>
+
+<para>
+When using the OBJLOADER package within the HTTP server a number of functions 
+are automatically added to the externals table of the OBJLOADER package. These
+functions are likely to be used inside the library and the relocator need to 
+have a pointer to them. In order to add more functions, see the OBJLOADER
+documentation. The complete list of the functions automatically added is:
+</para>
+
+<itemizedlist>
+  <listitem><para>cyg_httpd_start_chunked()</para></listitem>
+  <listitem><para>cyg_httpd_write_chunked()</para></listitem>
+  <listitem><para>cyg_httpd_end_chunked()</para></listitem>
+  <listitem><para>cyg_httpd_write()</para></listitem>
+  <listitem><para>cyg_httpd_find_form_variable()</para></listitem>
+  <listitem><para>cyg_httpd_find_ires()</para></listitem>
+  <listitem><para>cyg_httpd_send_ires()</para></listitem>
+  <listitem><para>diag_printf()</para></listitem>
+  <listitem><para>cyg_httpd_format_header()</para></listitem>
+  <listitem><para>cyg_httpd_find_mime_string()</para></listitem>
+</itemizedlist>
+
+<para>Every time the web client issues a GET or POST request for a file with an 
+extension of '.o'in the /cgi-bin directory (or whatever path the user chooses 
+to hold the libraries) then the library by that name is loaded, run and
+when the execution is over, it is dumped from memory.
+
+The library must be compiled separately, using the same toolchain used to 
+compile the server and then added to the file system.</para>
+
+<para>In order to reduce the footprint of the server, CGI through OBJLOADER
+can be compiled out by unchecking CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+in the configuration tool.</para>
+</sect2>
+
+<sect2 id="athttpd-cgi-tcl">
+<title>CGI via the simple tcl interpreter</title>
+<para>A small tcl interpreter has been added to the web server, and it can
+be used to write simple cgi scripts. The interpreter is admittedly very
+minimal, and it is only useful for very simple applications, but it is an
+excellent starting point for further development.</para>
+
+<para>In order for the scripting language to be useful, it has to access
+the form variables passed on during the GET or POST request. Because of
+this, all form variables registered with the CYG_HTTPD_FVAR_TABLE_ENTRY()
+macro are accessible via tcl. For example, if we have registered a
+form variable called foo, and during the GET request we are defining foo
+as being "1":</para>
+
+<programlisting width=72>GET /myForm.cgi?foo=1</programlisting>
+
+<para>then tcl will be able to access the variable foo as $foo. The data
+in the body of a POST request is also accessible through the use of the variable
+$post_data. This is useful if the data is not in "multipart/form-data"
+and tcl has to perform any type of processing on the data itself.</para>
+
+<para>In order to send back a response to the client a few functions have been
+added to the interpreter. These functions are:</para>
+
+<sect3 id="athttpd-start-chunked">
+<title>start_chunked</title>
+<programlisting width=72>start_chunked "extension";</programlisting>
+<para>"extension" is a string used to search the 
+table of the mime types. For example, to send back to the client an HTML file, 
+we can use: start_chunked "html";
+</para>
+</sect3>
+
+<sect3 id="athttpd-write-chunked">
+<title>write_chunked</title>
+<programlisting width=72>write_chunked content;</programlisting>
+<para>content is a string to send back to the client. 
+</para>
+</sect3>
+
+<sect3 id="athttpd-end-chunked">
+<title>end_chunked</title>
+<programlisting width=72>end_chunked;</programlisting>
+<para>No parameters. Send back an end of frame to the client.</para>
+</sect3>
+
+<sect3 id="athttpd-tcl-hello-world">
+<title>tcl hello world example</title>
+<para>
+The following example demonstrates how to send a log file in the file
+<filename>/ram/log</filename> to a web client. It replaces
+newline characters with <literal>&lt;br&gt;</literal> so that it is formatted on the
+browser correctly.
+<programlisting width=72>
+start_chunked "html";
+
+set fp [aio.open "/ram/log" r];
+$fp seek 0 end;
+set fsize [$fp tell];
+$fp seek 0 start;
+set data "abcxxx";
+set data [$fp read $fsize];
+$fp close;
+set data [string map {\n &lt;br&gt;} $data];
+
+set datax "";
+append datax "&lt;html&gt;&lt;body&gt;" $data "&lt;/body&gt;&lt;/html&gt;";
+
+write_chunked $datax;
+end_chunked;
+</programlisting>
+</para>
+<para>
+The above file should exist on a filesystem
+on the embedded target within its <filename class=directory>cgi-bin</filename>
+directory, for example as <filename>/cgi-bin/hello.tcl</filename>. Thereafter
+it may be accessed at the URL
+<literal>http://<replaceable>TARGET_NAME</replaceable>/cgi-bin/hello.tcl</literal>.
+</para>
+</sect3>
+</sect2>
+</sect1>
+
+<sect1 id="athttpd-authentication">
+<title>Authentication</title>
+<para>
+The server supports both Basic (base64) and Digest (MD5) authentication, 
+although they have not been tested with all clients. In this implementation, 
+the contents of certain directories of the file system can be protected, such
+that the user will be required to issue a username/password to access the
+content of the directory.</para>
+
+<para>To protect a directory with a basic authentication, there is a 
+specific macro:</para>
+
+<programlisting>
+CYG_HTTPD_AUTH_TABLE_ENTRY(entry, path, domain, un, pw, mode)
+
+entry            : an identifier unique to this entry.
+path             : the path to the directory whose content must be
+                    authenticated before it is sent out
+domain           : a domain identifier for this directory.
+un               : username for authentication
+pw               : password for authentication
+mode             : CYG_HTTPD_AUTH_BASIC for base64 encoding or 
+                   CYG_HTTPD_AUTH_DIGEST for MD5 encoding
+</programlisting>
+
+<para>for example, to require basic authentication of the content of directory 
+"/ecos/" with a username of "foo" and password "bar", the following is used:
+</para>
+
+<programlisting>
+CYG_HTTPD_AUTH_TABLE_ENTRY(hal_domain1_entry,          \
+                           "/ecos/",    "ecos_domain", \
+                           "foo",       "bar",         \
+                           CYG_HTTPD_AUTH_BASIC);
+</programlisting>
+
+<para>Any request for a file in the directory /ecos/ will now trigger a
+credential check. These credentials, once provided, are automatically sent by
+the client for every request within the particular domain.</para>
+
+<para>It must be noticed that the path name set in the macro is relative to the
+HTML document directory, CYGDAT_NET_HTTPD_SERVEROPT_HTMLDIR and it is the
+first part of the path provided by the client request (including the leading
+slash).</para>
+
+<para>In order to reduce the footprint of the server, authentication
+is not enabled by default, and so the option CYGOPT_NET_ATHTTPD_USE_AUTH must
+be used to enable support for basic and digest authentication.</para>
+
+<para>The MD5 digest authentication support is implemented using the RSA
+Data Security, Inc. MD5 Message-Digest Algorithm. Derivative works with
+MD5 digest authentication included must be identified as "derived from the
+RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work. See the file md5.c within this
+package for license details.</para>
+</sect1>
+
+<sect1 id="athttpd-dirlist">
+<title>Directory Listing</title>
+
+<para>If the user issues a "GET" request with a URL terminating in a slash, the
+server will try to locate one of the following index files in the directory,
+choosing one in the following order:</para>
+
+<itemizedlist>
+  <listitem><para>index.html</para></listitem>
+  <listitem><para>index.htm</para></listitem>
+  <listitem><para>default.html</para></listitem>
+  <listitem><para>home.html</para></listitem>
+</itemizedlist>
+
+<para>If any of these files is found, its contents are sent back
+to the client. If no such file is found the server uses the user-provided
+index file name (if any is specified with the CYGDAT_NET_ATHTTPD_ALTERNATE_HOME
+setting. Failing all this a directory listing is sent.</para>
+
+<para>Trailing slash redirection for directory names is supported.</para>
+
+<para>In order to reduce the footprint of the server, directory listing can
+be disabled by unchecking CYGOPT_NET_ATHTTPD_USE_DIRLIST. The savings are
+substantial since directory listing also makes use of a few internal
+resources (gif files) which are also compiled out.</para>
+</sect1>
+
+<sect1 id="athttpd-formvars">
+<title>Form Variables</title>
+
+<para>The server will automatically try to parse form variables when a form is
+submitted in the following cases:
+
+<itemizedlist>
+  <listitem><para>In a GET request, when the URL is followed by a question
+                  mark sign</para></listitem>
+  <listitem><para>In a POST request, when the the 'Content-Type' header line
+                  is set to 'application/x-www-form-urlencoded'</para></listitem>
+</itemizedlist>
+
+The variable names to look for during the parsing are held in
+an eCos table. In order to take advantage of this feature, the user first
+adds the variable names to the table, which also requires providing a buffer 
+where the parsed value will eventually be stored. The values will then be
+available in the buffers during the processing of the request, presumably in
+the body of a c language callback or CGI script.</para>
+
+<para>For example, if the user wants two form variables, "foo" and "bar", to 
+be parsed automatically, those variable names must be added to the table 
+with the following macro:</para>
+
+<programlisting>
+CYG_HTTPD_FVAR_TABLE_ENTRY(entry, name, buffp, bufflen)
+
+entry            : an identifier unique to this entry.
+name             : name of the form variable
+buffp            : a pointer to a buffer of characters where to store the value
+                   of the form variable.
+bufflen          : The length of the buffer. Must include a trailing string
+                   terminator.
+</programlisting>
+
+<para>or, in the specific instance mentioned above:</para>
+
+<programlisting>
+#define HTML_VAR_LEN   20
+char var_foo[HTML_VAR_LEN];
+char var_bar[HTML_VAR_LEN];
+CYG_HTTPD_FVAR_TABLE_ENTRY(hal_form_entry_foo, "foo", var_foo, HTML_VAR_LEN);
+CYG_HTTPD_FVAR_TABLE_ENTRY(hal_form_entry_bar, "bar", var_bar, HTML_VAR_LEN);
+</programlisting>
+
+<para>and after the GET or POST submissions, the list will contain the value 
+for "foo" and "bar" (if they were found in the form data.) It is the 
+responsability of the user to make sure that the buffer is large enough
+to hold all the data parsed (including the string terminator). The parser will
+write only up to the length of the buffer minus one (the last being the
+terminator) and discard any additional data.</para>
+
+<para>The values parsed are likely going to be used in c language callback, or
+in CGI files. In a c language callback the user can directly access the pointers
+of individual variables for further processing, keeping in mind that the parsing 
+always result in a string of characters to be produced, and any conversion
+(e.g. from strings to integer) must be performed within the callback. In
+a TCL script the user can just access a variable by its name. For example,
+in the case of the variables 'foo' and 'bar' shown above, it is possible
+to do something like 'write_chunked "You wrote $foo". The data that was sent in
+the body of a POST request is accessible in through a variable called
+'post_data'. In CGI functions
+implemented using the objloader the pointers to the
+variables cannot be accessed directly, since the library will likely not
+know their location in memory. The proper way to access them is by using the
+cyg_httpd_find_form_variable() function from within the library:</para>
+
+<programlisting>
+char* cyg_httpd_find_form_variable(char* name)
+
+name             : name of the form variable to look up
+
+returns a pointer to the buffer, or 0 if the variable was not found.
+</programlisting>
+
+<para>When using the OBJLOADER package within the web server, an entry
+for the cyg_httpd_find_form_variable() function is automatically added to the
+externals table the OBJLOADER for relocation. See the OBLOADER paragraph of 
+the ATHTTP user's guide for the full list of the exported functions.</para>
+
+<para>In order to avoid stale data, all the buffers in the table are cleared
+before running the parser and thus any variable in the list that was not
+assigned a new value dureing the request will be an empty string.</para>
+</sect1>
+
+<sect1 id="athttpd-ires">
+<title>Internal Resources</title>
+
+<para>When the server does not use a file system the user must be responsible
+to provide a C language callback function for each URL that will be
+requested by the client. This means locating the data and sending it out
+using either <command>cyg_httpd_write()</command> or
+<command>cyg_httpd_write_chunked()</command>.</para>
+
+<para>In order to simplify this process the server allows registering
+any number of URLs as internal resources, by providing the URL name, the
+pointer to the resource data and its size. When a URL is requested the
+server will look it up among all internal resources, and if found, it
+will send out the resource.</para>
+
+<para>Internal resource can also be used along with a file system. In this
+case the file system is searched first, and if a file is found, it it
+sent. If a file is not found, the internal resources are searched and
+if a match if found it is sent.</para>
+
+<para>The drawback of this approach is, of course, that all these
+resources are going to add to the size of the operating system image, and thus
+it should be used only when memory is not a major constraint of the 
+design.</para>
+
+<para>As always, to provide this type of customization, ecos tables are used.
+The format for adding a new resource to the internal table is the following:
+</para>
+
+<programlisting>
+CYG_HTTPD_IRES_TABLE_ENTRY(entry, name, buffp, len)
+
+entry            : an identifier unique to this entry.
+name             : name of the URL including leading '/'
+buffp            : a pointer to a buffer of characters where to store the value
+                   of the form variable.
+len              : size of the array                   
+</programlisting>
+
+<para>As an example, if the user wants to provide his own web page by
+hardcoding it in the application code, here is how he would do it:</para>
+
+<programlisting>
+#define MY_OWN_HOME_PAGE "eCos RTOS"
+CYG_HTTPD_IRES_TABLE_ENTRY(cyg_httpd_ires_home,       \
+                           "/index.html",             \
+                           MY_OWN_HOME_PAGE,          \
+                           9);
+</programlisting>
+
+<para>The extension of the file name determines the MIME type to be used for
+internal resources.</para>
+
+<para>When using directory listing you are implicitly making use of internal
+resources. The small icons that appear to the left of file names and
+directories are internal resources. Unchecking CYGOPT_NET_HTTP_USE_DIRLIST
+will prevent the addition of these files.</para>
+
+<para>In order to use internal resources, a generic file must first be
+turned into a c language array, which is then compiled in the application
+code. To create this array you can use the tcl script that comes with the
+ecos distribution at packages/fs/rom/current/support/file2.tcl.</para>
+</sect1>
+</chapter>
+</part>
diff --git a/packages/net/athttpd/v2_0/doc/mime_types.txt b/packages/net/athttpd/v2_0/doc/mime_types.txt
new file mode 100644 (file)
index 0000000..f22df57
--- /dev/null
@@ -0,0 +1,202 @@
+// mime_types.txt
+//
+// Because this web server is designed for small, constrained systems, there
+//  is no need to include all different MIME types. They would take up a
+//  considerable amount of memory and they would rarely, if ever, be used 
+//  since in embedded environments the type of web pages is mostly known
+//  upfront and only the MIME types for those pages can me inserted in the table.
+// At any rate, for those of you out there that feel shortchanged, this is a
+//  fairly long list of MIME types that I found out there. If you need any
+//  of them, add them to the mime table using the CYG_HTTPD_MIME_TABLE_ENTRY()
+//  macro.
+
+a       application/octet-stream
+aab     application/x-authorware-bin
+aam     application/x-authorware-map
+aas     application/x-authorware-seg
+ai      application/postscript
+aif     audio/x-aiff
+aifc    audio/x-aiff
+aiff    audio/x-aiff
+asc     text/plain
+asf     video/x-ms-asf
+asx     video/x-ms-asf
+au      audio/basic
+avi     video/x-msvideo
+bcpio   application/x-bcpio
+bin     application/octet-stream
+bmp     image/bmp
+cdf     application/x-netcdf
+class   application/x-java-vm
+cpio    application/x-cpio
+cpt     application/mac-compactpro
+crl     application/x-pkcs7-crl
+crt     application/x-x509-ca-cert
+csh     application/x-csh
+css     text/css
+dcr     application/x-director
+dir     application/x-director
+djv     image/vnd.djvu
+djvu    image/vnd.djvu
+dll     application/octet-stream
+dms     application/octet-stream
+doc     application/msword
+dtd     text/xml
+dump    application/octet-stream
+dvi     application/x-dvi
+dxr     application/x-director
+eps     application/postscript
+etx     text/x-setext
+exe     application/octet-stream
+ez      application/andrew-inset
+fgd     application/x-director
+fh      image/x-freehand
+fh4     image/x-freehand
+fh5     image/x-freehand
+fh7     image/x-freehand
+fhc     image/x-freehand
+gif     image/gif
+gtar    application/x-gtar
+hdf     application/x-hdf
+hqx     application/mac-binhex40
+htm     text/html; charset=%s
+html    text/html; charset=%s
+ice     x-conference/x-cooltalk
+ief     image/ief
+iges    model/iges
+igs     model/iges
+iv      application/x-inventor
+jar     application/x-java-archive
+jfif    image/jpeg
+jpe     image/jpeg
+jpeg    image/jpeg
+jpg     image/jpeg
+js      application/x-javascript
+kar     audio/midi
+latex   application/x-latex
+lha     application/octet-stream
+lzh     application/octet-stream
+m3u     audio/x-mpegurl
+man     application/x-troff-man
+mathml  application/mathml+xml
+me      application/x-troff-me
+mesh    model/mesh
+mid     audio/midi
+midi    audio/midi
+mif     application/vnd.mif
+mime    message/rfc822
+mml     application/mathml+xml
+mov     video/quicktime
+movie   video/x-sgi-movie
+mp2     audio/mpeg
+mp3     audio/mpeg
+mp4     video/mp4
+mpe     video/mpeg
+mpeg    video/mpeg
+mpg     video/mpeg
+mpga    audio/mpeg
+ms      application/x-troff-ms
+msh     model/mesh
+mv      video/x-sgi-movie
+mxu     video/vnd.mpegurl
+nc      application/x-netcdf
+o       application/octet-stream
+oda     application/oda
+ogg     application/x-ogg
+pac     application/x-ns-proxy-autoconfig
+pbm     image/x-portable-bitmap
+pdb     chemical/x-pdb
+pdf     application/pdf
+pgm     image/x-portable-graymap
+pgn     application/x-chess-pgn
+png     image/png
+pnm     image/x-portable-anymap
+ppm     image/x-portable-pixmap
+ppt     application/vnd.ms-powerpoint
+ps      application/postscript
+qt      video/quicktime
+ra      audio/x-realaudio
+ram     audio/x-pn-realaudio
+ras     image/x-cmu-raster
+rdf     application/rdf+xml
+rgb     image/x-rgb
+rm      audio/x-pn-realaudio
+roff    application/x-troff
+rpm     audio/x-pn-realaudio-plugin
+rss     application/rss+xml
+rtf     text/rtf
+rtx     text/richtext
+sgm     text/sgml
+sgml    text/sgml
+sh      application/x-sh
+shar    application/x-shar
+silo    model/mesh
+sit     application/x-stuffit
+skd     application/x-koan
+skm     application/x-koan
+skp     application/x-koan
+skt     application/x-koan
+smi     application/smil
+smil    application/smil
+snd     audio/basic
+so      application/octet-stream
+spl     application/x-futuresplash
+src     application/x-wais-source
+stc     application/vnd.sun.xml.calc.template
+std     application/vnd.sun.xml.draw.template
+sti     application/vnd.sun.xml.impress.template
+stw     application/vnd.sun.xml.writer.template
+sv4cpio application/x-sv4cpio
+sv4crc  application/x-sv4crc
+svg     image/svg+xml
+svgz    image/svg+xml
+swf     application/x-shockwave-flash
+sxc     application/vnd.sun.xml.calc
+sxd     application/vnd.sun.xml.draw
+sxg     application/vnd.sun.xml.writer.global
+sxi     application/vnd.sun.xml.impress
+sxm     application/vnd.sun.xml.math
+sxw     application/vnd.sun.xml.writer
+t       application/x-troff
+tar     application/x-tar
+tcl     application/x-tcl
+tex     application/x-tex
+texi    application/x-texinfo
+texinfo application/x-texinfo
+tif     image/tiff
+tiff    image/tiff
+tr      application/x-troff
+tsp     application/dsptype
+tsv     text/tab-separated-values
+txt     text/plain; charset=%s
+ustar   application/x-ustar
+vcd     application/x-cdlink
+vrml    model/vrml
+vx      video/x-rad-screenplay
+wav     audio/x-wav
+wax     audio/x-ms-wax
+wbmp    image/vnd.wap.wbmp
+wbxml   application/vnd.wap.wbxml
+wm      video/x-ms-wm
+wma     audio/x-ms-wma
+wmd     application/x-ms-wmd
+wml     text/vnd.wap.wml
+wmlc    application/vnd.wap.wmlc
+wmls    text/vnd.wap.wmlscript
+wmlsc   application/vnd.wap.wmlscriptc
+wmv     video/x-ms-wmv
+wmx     video/x-ms-wmx
+wmz     application/x-ms-wmz
+wrl     model/vrml
+wsrc    application/x-wais-source
+wvx     video/x-ms-wvx
+xbm     image/x-xbitmap
+xht     application/xhtml+xml
+xhtml   application/xhtml+xml
+xls     application/vnd.ms-excel
+xml     text/xml
+xpm     image/x-xpixmap
+xsl     text/xml
+xwd     image/x-xwindowdump
+xyz     chemical/x-xyz
+zip     application/zip
diff --git a/packages/net/athttpd/v2_0/include/auth.h b/packages/net/athttpd/v2_0/include/auth.h
new file mode 100644 (file)
index 0000000..062bd8c
--- /dev/null
@@ -0,0 +1,127 @@
+/* =================================================================
+ *
+ *      auth.h
+ *
+ *      Improved HTTPD server.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __AUTH_H__
+#define __AUTH_H__
+
+#include <pkgconf/system.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_tables.h>
+
+#define badchar(c,p) (!(p = memchr(b64string, c, 64)))
+
+extern cyg_uint8 *cyg_httpd_current_authName;
+
+typedef enum cyg_httpd_auth_type
+{
+    CYG_HTTPD_AUTH_BASIC = 0, 
+    CYG_HTTPD_AUTH_DIGEST = 1
+} cyg_httpd_auth_type;
+
+#define AUTH_STORAGE_BUFFER_LENGTH_LOGIN             32
+#define AUTH_STORAGE_BUFFER_LENGTH_PASSWORD          32
+#define AUTH_STORAGE_BUFFER_LENGTH        (AUTH_STORAGE_BUFFER_LENGTH_LOGIN +\
+                                           AUTH_STORAGE_BUFFER_LENGTH_PASSWORD)
+// It must be stressed that the auth_dirname field is the directory name
+//  that will be requested by the web server, and _not_ the absolute name
+//  in the eCos file system. 
+// Lets' make an example. Let's say that the files of your web site reside in 
+//  the directory '/fs/jffs2/html'. Your CYG_HTTPD_DEFAULT_PATH will likely be
+//  set to '/fs/jffs2/' and the CYG_HTTPD_DEFAULT_HTML_DIR will likely be
+//  set to 'html/'. The web server will then request a file 
+//  (i.e. 'images/foo.jpg') whose absolute location in the eCos file system is
+//  '/fs/jffs2/html/images/foo.jpg', and if we want to protect the 'images/'
+//  directory with some kind of authentication, the auth_dirname must be 
+//  pointing to a string such as "images/".
+struct cyg_httpd_auth_table_entry
+{
+    char                *auth_dirname;
+    char                *auth_domainname;
+    char                *auth_username;
+    char                *auth_password;
+    cyg_httpd_auth_type  auth_mode;
+} CYG_HAL_TABLE_TYPE;
+
+typedef struct cyg_httpd_auth_table_entry cyg_httpd_auth_table_entry;
+#define CYG_HTTPD_AUTH_TABLE_ENTRY( __name, __path, __domain, __un, __pw, __mode )  \
+ cyg_httpd_auth_table_entry __name CYG_HAL_TABLE_ENTRY( httpd_auth_table ) =  \
+                             { __path, __domain, __un, __pw, __mode } 
+
+cyg_httpd_auth_table_entry* cyg_httpd_auth_entry_from_path(char *);
+cyg_httpd_auth_table_entry* cyg_httpd_auth_entry_from_domain(char *);
+cyg_httpd_auth_table_entry* cyg_httpd_is_authenticated(char*);
+char* cyg_httpd_digest_data(char *, char *);
+char* cyg_httpd_digest_skip(char *);
+
+// The following code is a slightly modified version of those available at the
+//  end of RFC1270.
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+
+//extern char cyg_httpd_md5_username[];
+//extern char cyg_httpd_md5_opaque[];
+//extern char cyg_httpd_md5_alg[];
+//extern char cyg_httpd_md5_realm[];
+extern char cyg_httpd_md5_nonce[];
+extern char cyg_httpd_md5_cnonce[];
+extern char cyg_httpd_md5_digest[];
+extern char cyg_httpd_md5_qop[];
+extern char cyg_httpd_md5_response[];
+extern char cyg_httpd_md5_noncecount[];
+extern char cyg_httpd_md5_ha2[];
+extern char cyg_httpd_md5_ha1[];
+
+#endif // __AUTH_H__
diff --git a/packages/net/athttpd/v2_0/include/cgi.h b/packages/net/athttpd/v2_0/include/cgi.h
new file mode 100644 (file)
index 0000000..1e81d9e
--- /dev/null
@@ -0,0 +1,61 @@
+/* =================================================================
+ *
+ *      cgi.h
+ *
+ *      
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __CGI_H__
+#define __CGI_H__
+
+cyg_int32 cyg_httpd_exec_cgi(void);
+void cyg_httpd_init_tcl_interpreter(void);
+
+#endif
diff --git a/packages/net/athttpd/v2_0/include/digcalc.h b/packages/net/athttpd/v2_0/include/digcalc.h
new file mode 100644 (file)
index 0000000..e7d53b3
--- /dev/null
@@ -0,0 +1,30 @@
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+#define IN
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+    IN char * pszAlg,
+    IN char * pszUserName,
+    IN char * pszRealm,
+    IN char * pszPassword,
+    IN char * pszNonce,
+    IN char * pszCNonce,
+    OUT HASHHEX SessionKey
+    );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+    IN HASHHEX HA1,           /* H(A1) */
+    IN char * pszNonce,       /* nonce from server */
+    IN char * pszNonceCount,  /* 8 hex digits */
+    IN char * pszCNonce,      /* client nonce */
+    IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
+    IN char * pszMethod,      /* method from the request */
+    IN char * pszDigestUri,   /* requested URL */
+    IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
+    OUT HASHHEX Response      /* request-digest or response-digest */
+    );
diff --git a/packages/net/athttpd/v2_0/include/forms.h b/packages/net/athttpd/v2_0/include/forms.h
new file mode 100644 (file)
index 0000000..1a1794b
--- /dev/null
@@ -0,0 +1,79 @@
+/* =================================================================
+ *
+ *      forms.h
+ *
+ *      Improved HTTPD server.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __FORMS_H__
+#define __FORMS_H__
+
+struct cyg_httpd_fvars_table_entry
+{
+    char *name;
+    char *buf; 
+    int  buflen; 
+} CYG_HAL_TABLE_TYPE;
+
+typedef struct cyg_httpd_fvars_table_entry cyg_httpd_fvars_table_entry;
+
+#define CYG_HTTPD_FVAR_TABLE_ENTRY(__name, __fvar, __val, __len) \
+cyg_httpd_fvars_table_entry __name CYG_HAL_TABLE_ENTRY( httpd_fvars_table ) = \
+                                                      {__fvar, __val, __len} 
+
+__externC cyg_httpd_fvars_table_entry cyg_httpd_fvars_table[];
+__externC cyg_httpd_fvars_table_entry cyg_httpd_fvars_table_end[];
+
+// Prototypes.
+char *cyg_httpd_store_form_data(char*);
+void cyg_httpd_handle_method_POST(void);
+cyg_int8 cyg_httpd_from_hex (cyg_int8);
+char *cyg_httpd_find_form_variable(char*);
+#endif
diff --git a/packages/net/athttpd/v2_0/include/global.h b/packages/net/athttpd/v2_0/include/global.h
new file mode 100644 (file)
index 0000000..e6c689c
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+  function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+  been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+  returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif
diff --git a/packages/net/athttpd/v2_0/include/handler.h b/packages/net/athttpd/v2_0/include/handler.h
new file mode 100644 (file)
index 0000000..028be12
--- /dev/null
@@ -0,0 +1,99 @@
+/* =================================================================
+ *
+ *      handler.h
+ *
+ *      Improved HTTPD server.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __HANDLER_H__
+#define __HANDLER_H__
+
+// =============================================================================
+// Internal Resources
+// =============================================================================
+struct cyg_httpd_ires_table_entry
+{
+    char *f_pname;
+    char *f_ptr;
+    int   f_size; 
+} CYG_HAL_TABLE_TYPE;
+
+typedef struct cyg_httpd_ires_table_entry cyg_httpd_ires_table_entry;
+
+#define CYG_HTTPD_IRES_TABLE_ENTRY(__name, __path_name, __pmem, __size) \
+cyg_httpd_ires_table_entry __name \
+   CYG_HAL_TABLE_ENTRY(httpd_ires_table) = {(char*)__path_name, \
+                                            (char*)__pmem, (int)__size} 
+      
+cyg_httpd_ires_table_entry *cyg_httpd_find_ires(char *);
+void cyg_httpd_send_ires(cyg_httpd_ires_table_entry *);
+
+// =============================================================================
+// C callbacks
+// =============================================================================
+typedef cyg_int32  (*handler)(CYG_HTTPD_STATE*);
+struct cyg_httpd_handler_table_entry
+{
+    char     *path;
+    handler   h;
+} CYG_HAL_TABLE_TYPE;
+
+typedef struct cyg_httpd_handler_table_entry cyg_httpd_handler_table_entry;
+
+#define CYG_HTTPD_HANDLER_TABLE_ENTRY(__name, __pattern, __arg) \
+cyg_httpd_handler_table_entry __name \
+      CYG_HAL_TABLE_ENTRY(httpd_handler_table) = { __pattern, __arg } 
+
+handler cyg_httpd_find_handler(void);
+cyg_int32 cyg_httpd_exec_cgi(void);
+void cyg_httpd_send_directory_listing(char*);
+
+#endif
+
diff --git a/packages/net/athttpd/v2_0/include/http.h b/packages/net/athttpd/v2_0/include/http.h
new file mode 100644 (file)
index 0000000..112c654
--- /dev/null
@@ -0,0 +1,226 @@
+/* =================================================================
+ *
+ *      http.h
+ *
+ *      Improved HTTPD server.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __HTTP_H__
+#define __HTTP_H__
+
+#include <pkgconf/system.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_tables.h>
+
+#include <pkgconf/athttpd.h>
+#include <cyg/athttpd/auth.h>
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
+#include <cyg/athttpd/jim.h>
+#endif
+
+
+typedef enum cyg_httpd_req_type
+{
+    CYG_HTTPD_METHOD_GET  = 1,
+    CYG_HTTPD_METHOD_HEAD = 2,
+    CYG_HTTPD_METHOD_POST = 3
+} cyg_httpd_req_type;
+
+#define CYG_HTTPD_MAXURL                    128
+#define CYG_HTTPD_MAXPATH                   128
+
+#define CYG_HTTPD_MAXINBUFFER               CYGNUM_ATHTTPD_SERVER_BUFFER_SIZE
+#define CYG_HTTPD_MAXOUTBUFFER              CYGNUM_ATHTTPD_SERVER_BUFFER_SIZE
+
+#define CYG_HTTPD_DEFAULT_CGIBIN_OBJLOADER_EXTENSION ".o"
+#define CYG_HTTPD_DEFAULT_CGIBIN_TCL_EXTENSION       ".tcl"
+
+#define CYG_HTTPD_TIME_STRING_LEN                 32
+
+#define CYG_HTTPD_STATUS_OK                      200
+#define CYG_HTTPD_STATUS_MOVED_PERMANENTLY       301
+#define CYG_HTTPD_STATUS_MOVED_TEMPORARILY       302
+#define CYG_HTTPD_STATUS_NOT_MODIFIED            304
+#define CYG_HTTPD_STATUS_BAD_REQUEST             400
+#define CYG_HTTPD_STATUS_NOT_AUTHORIZED          401
+#define CYG_HTTPD_STATUS_FORBIDDEN               403
+#define CYG_HTTPD_STATUS_NOT_FOUND               404
+#define CYG_HTTPD_STATUS_METHOD_NOT_ALLOWED      405
+#define CYG_HTTPD_STATUS_SYSTEM_ERROR            500
+#define CYG_HTTPD_STATUS_NOT_IMPLEMENTED         501
+
+#define CYG_HTTPD_MODE_CLOSE_CONN             0x0001
+#define CYG_HTTPD_MODE_TRANSFER_CHUNKED       0x0002
+#define CYG_HTTPD_MODE_SEND_HEADER_ONLY       0x0004
+#define CYG_HTTPD_MODE_NO_CACHE               0x0008
+#define CYG_HTTPD_MODE_FORM_DATA              0x0010
+
+// This must be generated at random...
+#define CYG_HTTPD_MD5_AUTH_NAME                "MD5"
+#define CYG_HTTPD_MD5_AUTH_QOP                 "auth"
+#define CYG_HTTPD_MD5_AUTH_OPAQUE              "0000000000000000"
+
+#define TIME_FORMAT_RFC1123                    "%a, %d %b %Y %H:%H:%S GMT"
+
+typedef struct __socket_entry
+{
+    cyg_int32 descriptor;
+    time_t    timestamp;
+} socket_entry; 
+
+// =============================================================================
+// Main HTTP structure.
+// =============================================================================
+typedef struct
+{
+    cyg_httpd_req_type method;    
+    fd_set       rfds;
+
+    cyg_int32    host[4];
+
+    char         url[CYG_HTTPD_MAXURL+1];
+    char         inbuffer[CYG_HTTPD_MAXINBUFFER+1];
+    cyg_int32    inbuffer_len, content_len;
+    
+    // Packet status.
+    //
+    //   bit      Description
+    // -------------------------------------------------------------------------
+    //    0       A 1 means that the connection will be closed after the request
+    //             has been served (i.e. Connection: close" will appear in
+    //             the header. Otherwise the connection will be kept alive
+    //             "Connection: keep-alive"
+    //    1       Set when the transfer will be chunked
+    //    2       Set when the we need to send only the header
+    //    3       Set when the we do not want this document to be cached (i.e.
+    //             "Cache-Control: no-cache" will appear in the header) which
+    //             is meant for c language callbacks and GCI.
+    //    4       Set when the the frame we just received contains form data.
+    //             In this case we call the function that parsed the data into
+    //             user-defined form variables.
+    cyg_uint16   mode;
+    
+    // Ouptut data.
+    cyg_uint16   status_code;
+    char        *mime_type;
+    cyg_int32    payload_len;
+    char         outbuffer[CYG_HTTPD_MAXOUTBUFFER+1];
+    
+    socket_entry sockets[CYGPKG_NET_MAXSOCKETS];
+    cyg_int32    fdmax;
+    
+    // Socket handle.
+    cyg_int32    client_index;
+
+    // Modified-since is always reset to -1 before parsing the headers of a
+    //  request. If the "Modified-Since" element is present in the header then
+    //  we'll copy the value in this variable, otherwise it will remain to -1.
+    // This will tell us if we can send a CYG_HTTPD_STATUS_NOT_MODIFIED back to
+    //  the client or instead we'll have to send the whole page again.
+    time_t       modified_since;
+    time_t       last_modified;
+    
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
+    Jim_Interp *jim_interp;
+#endif    
+
+    // Pointer to the data immediately following the last byte of the header.
+    // In a POST request, this is where the goods are. After the post request
+    //  is handles it will point to the start of the new request, if any.
+    char        *request_end;
+
+    // This pointer points to the buffer where we collected all the post
+    //  data (it might come in more than one frame)  and must be visible to
+    //  handlers and cgi scripts.
+    char        *post_data;
+
+    // This pointer points to the information about the domain that needs
+    //  to be authenticated. It is only used by the function that builds the
+    //  header.
+    cyg_httpd_auth_table_entry *needs_auth;
+
+    struct sockaddr_in server_conn;
+    struct sockaddr_in client_conn;
+} CYG_HTTPD_STATE;
+
+extern CYG_HTTPD_STATE httpstate;
+
+extern const char *day_of_week[];
+extern const char *month_of_year[]; 
+
+struct cyg_httpd_mime_table_entry
+{
+    char *extension;
+    char *mime_string;
+} CYG_HAL_TABLE_TYPE;
+
+typedef struct cyg_httpd_mime_table_entry cyg_httpd_mime_table_entry;
+
+#define CYG_HTTPD_MIME_TABLE_ENTRY(__name, __pattern, __arg) \
+cyg_httpd_mime_table_entry __name CYG_HAL_TABLE_ENTRY(httpd_mime_table) = \
+                                                          { __pattern, __arg } 
+
+extern cyg_int32 debug_print;
+
+void cyg_httpd_set_home_page(cyg_int8*);
+char* cyg_httpd_find_mime_string(char*);
+cyg_int32 cyg_httpd_initialize(void);
+void cyg_httpd_cleanup_filename(char*);
+char* cyg_httpd_parse_GET(char*);
+char* cyg_httpd_parse_POST(char*);
+void cyg_httpd_handle_method_GET(void);
+void cyg_httpd_handle_method_HEAD(void);
+void cyg_httpd_process_method(void);
+void cyg_httpd_send_file(char*);
+void cyg_httpd_send_error(cyg_int32);
+cyg_int32 cyg_httpd_format_header(void);
+
+#endif
diff --git a/packages/net/athttpd/v2_0/include/jim.h b/packages/net/athttpd/v2_0/include/jim.h
new file mode 100644 (file)
index 0000000..8ce202d
--- /dev/null
@@ -0,0 +1,954 @@
+/* Jim - A small embeddable Tcl interpreter
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ *
+ * $Id$
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * A copy of the license is also included in the source distribution
+ * of Jim, as a TXT file name called LICENSE.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <limits.h>
+#include <stdio.h>  /* for the FILE typedef definition */
+#include <stdlib.h> /* In order to export the Jim_Free() macro */
+
+/* -----------------------------------------------------------------------------
+* Some /very/ old compiler maybe do not know how to
+* handle 'const'. They even do not know, how to ignore
+* it. For those compiler it may be better to compile with
+* define JIM_NO_CONST activated
+* ---------------------------------------------------------------------------*/
+
+#ifdef JIM_NO_CONST
+#  define const
+#endif
+
+/* -----------------------------------------------------------------------------
+ * System configuration
+ * For most modern systems, you can leave the default.
+ * For embedded systems some change may be required.
+ * ---------------------------------------------------------------------------*/
+
+#define HAVE_LONG_LONG
+
+/* -----------------------------------------------------------------------------
+ * Compiler specific fixes.
+ * ---------------------------------------------------------------------------*/
+
+/* MSC has _stricmp instead of strcasecmp */
+#ifdef _MSC_VER
+#  define strcasecmp _stricmp
+#endif /* _MSC_VER */
+
+/* Long Long type and related issues */
+#ifdef HAVE_LONG_LONG
+#  ifdef _MSC_VER /* MSC compiler */
+#    define jim_wide _int64
+#    ifndef LLONG_MAX
+#      define LLONG_MAX    9223372036854775807I64
+#    endif
+#    ifndef LLONG_MIN
+#      define LLONG_MIN    (-LLONG_MAX - 1I64)
+#    endif
+#    define JIM_WIDE_MIN LLONG_MIN
+#    define JIM_WIDE_MAX LLONG_MAX
+#  else /* Other compilers (mainly GCC) */
+#    define jim_wide long long
+#    ifndef LLONG_MAX
+#      define LLONG_MAX    9223372036854775807LL
+#    endif
+#    ifndef LLONG_MIN
+#      define LLONG_MIN    (-LLONG_MAX - 1LL)
+#    endif
+#    define JIM_WIDE_MIN LLONG_MIN
+#    define JIM_WIDE_MAX LLONG_MAX
+#  endif
+#else
+#  define jim_wide long
+#  define JIM_WIDE_MIN LONG_MIN
+#  define JIM_WIDE_MAX LONG_MAX
+#endif
+
+/* -----------------------------------------------------------------------------
+ * LIBC specific fixes
+ * ---------------------------------------------------------------------------*/
+
+#ifdef HAVE_LONG_LONG
+# if defined(_MSC_VER) || defined(__MSVCRT__)
+#    define JIM_WIDE_MODIFIER "I64d"
+# else
+#    define JIM_WIDE_MODIFIER "lld"
+# endif
+#else
+#    define JIM_WIDE_MODIFIER "ld"
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Exported defines
+ * ---------------------------------------------------------------------------*/
+
+/* Jim version numbering: every version of jim is marked with a
+ * successive integer number. This is version 0. The first
+ * stable version will be 1, then 2, 3, and so on. */
+#define JIM_VERSION 51
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_EVAL 5
+#define JIM_EXIT 6
+#define JIM_MAX_NESTING_DEPTH 10000 /* default max nesting depth */
+
+/* Some function get an integer argument with flags to change
+ * the behaviour. */
+#define JIM_NONE 0    /* no flags set */
+#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
+
+/* Flags for Jim_SubstObj() */
+#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
+#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
+#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
+
+/* Unused arguments generate annoying warnings... */
+#define JIM_NOTUSED(V) ((void) V)
+
+/* Flags used by API calls getting a 'nocase' argument. */
+#define JIM_CASESENS    0   /* case sensitive */
+#define JIM_NOCASE      1   /* no case */
+
+/* Filesystem related */
+#define JIM_PATH_LEN 1024
+
+/* Newline, some embedded system may need -DJIM_CRLF */
+#ifdef JIM_CRLF
+#define JIM_NL "\r\n"
+#else
+#define JIM_NL "\n"
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Stack
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_Stack {
+    int len;
+    int maxlen;
+    void **vector;
+} Jim_Stack;
+
+/* -----------------------------------------------------------------------------
+ * Hash table
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_HashEntry {
+    const void *key;
+    void *val;
+    struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+    unsigned int (*hashFunction)(const void *key);
+    const void *(*keyDup)(void *privdata, const void *key);
+    void *(*valDup)(void *privdata, const void *obj);
+    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+    void (*keyDestructor)(void *privdata, const void *key);
+    void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+    Jim_HashEntry **table;
+    Jim_HashTableType *type;
+    unsigned int size;
+    unsigned int sizemask;
+    unsigned int used;
+    unsigned int collisions;
+    void *privdata;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+    Jim_HashTable *ht;
+    int index;
+    Jim_HashEntry *entry, *nextEntry;
+} Jim_HashTableIterator;
+
+/* This is the initial size of every hash table */
+#define JIM_HT_INITIAL_SIZE     16
+
+/* ------------------------------- Macros ------------------------------------*/
+#define Jim_FreeEntryVal(ht, entry) \
+    if ((ht)->type->valDestructor) \
+        (ht)->type->valDestructor((ht)->privdata, (entry)->val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+    if ((ht)->type->valDup) \
+        entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
+    else \
+        entry->val = (_val_); \
+} while(0)
+
+#define Jim_FreeEntryKey(ht, entry) \
+    if ((ht)->type->keyDestructor) \
+        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+    if ((ht)->type->keyDup) \
+        entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+    else \
+        entry->key = (_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+    (((ht)->type->keyCompare) ? \
+        (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+        (key1) == (key2))
+
+#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->val)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj structure
+ * ---------------------------------------------------------------------------*/
+
+/* -----------------------------------------------------------------------------
+ * Jim object. This is mostly the same as Tcl_Obj itself,
+ * with the addition of the 'prev' and 'next' pointers.
+ * In Jim all the objects are stored into a linked list for GC purposes,
+ * so that it's possible to access every object living in a given interpreter
+ * sequentially. When an object is freed, it's moved into a different
+ * linked list, used as object pool.
+ *
+ * The refcount of a freed object is always -1.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Obj {
+    int refCount; /* reference count */
+    char *bytes; /* string representation buffer. NULL = no string repr. */
+    int length; /* number of bytes in 'bytes', not including the numterm. */
+    struct Jim_ObjType *typePtr; /* object type. */
+    /* Internal representation union */
+    union {
+        /* integer number type */
+        jim_wide wideValue;
+        /* hashed object type value */
+        int hashValue;
+        /* index type */
+        int indexValue;
+        /* return code type */
+        int returnCode;
+        /* double number type */
+        double doubleValue;
+        /* Generic pointer */
+        void *ptr;
+        /* Generic two pointers value */
+        struct {
+            void *ptr1;
+            void *ptr2;
+        } twoPtrValue;
+        /* Variable object */
+        struct {
+            unsigned jim_wide callFrameId;
+            struct Jim_Var *varPtr;
+        } varValue;
+        /* Command object */
+        struct {
+            unsigned jim_wide procEpoch;
+            struct Jim_Cmd *cmdPtr;
+        } cmdValue;
+        /* List object */
+        struct {
+            struct Jim_Obj **ele;    /* Elements vector */
+            int len;        /* Length */
+            int maxLen;        /* Allocated 'ele' length */
+        } listValue;
+        /* String type */
+        struct {
+            int maxLength;
+        } strValue;
+        /* Reference type */
+        struct {
+            jim_wide id;
+            struct Jim_Reference *refPtr;
+        } refValue;
+        /* Source type */
+        struct {
+            const char *fileName;
+            int lineNumber;
+        } sourceValue;
+        /* Dict substitution type */
+        struct {
+            struct Jim_Obj *varNameObjPtr;
+            struct Jim_Obj *indexObjPtr;
+        } dictSubstValue;
+        /* tagged binary type */
+        struct {
+            unsigned char *data;
+            size_t         len;
+        } binaryValue;
+    } internalRep;
+    /* This are 8 or 16 bytes more for every object
+     * but this is required for efficient garbage collection
+     * of Jim references. */
+    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
+    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
+} Jim_Obj;
+
+/* Jim_Obj related macros */
+#define Jim_IncrRefCount(objPtr) \
+    ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+    if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+    ((objPtr)->refCount > 1)
+
+/* This macro is used when we allocate a new object using
+ * Jim_New...Obj(), but for some error we need to destroy it.
+ * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
+ * can just call Jim_FreeNewObj. To call Jim_Free directly
+ * seems too raw, the object handling may change and we want
+ * that Jim_FreeNewObj() can be called only against objects
+ * that are belived to have refcount == 0. */
+#define Jim_FreeNewObj Jim_FreeObj
+
+/* Free the internal representation of the object. */
+#define Jim_FreeIntRep(i,o) \
+    if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+        (o)->typePtr->freeIntRepProc(i, o)
+
+/* Get the internal representation pointer */
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+/* Set the internal representation pointer */
+#define Jim_SetIntRepPtr(o, p) \
+    (o)->internalRep.ptr = (p)
+
+/* The object type structure.
+ * There are four methods.
+ *
+ * - FreeIntRep is used to free the internal representation of the object.
+ *   Can be NULL if there is nothing to free.
+ * - DupIntRep is used to duplicate the internal representation of the object.
+ *   If NULL, when an object is duplicated, the internalRep union is
+ *   directly copied from an object to another.
+ *   Note that it's up to the caller to free the old internal repr of the
+ *   object before to call the Dup method.
+ * - UpdateString is used to create the string from the internal repr.
+ * - setFromAny is used to convert the current object into one of this type.
+ */
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+    
+typedef struct Jim_ObjType {
+    const char *name; /* The name of the type. */
+    Jim_FreeInternalRepProc *freeIntRepProc;
+    Jim_DupInternalRepProc *dupIntRepProc;
+    Jim_UpdateStringProc *updateStringProc;
+    int flags;
+} Jim_ObjType;
+
+/* Jim_ObjType flags */
+#define JIM_TYPE_NONE 0        /* No flags */
+#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
+
+/* Starting from 1 << 20 flags are reserved for private uses of
+ * different calls. This way the same 'flags' argument may be used
+ * to pass both global flags and private flags. */
+#define JIM_PRIV_FLAG_SHIFT 20
+
+/* -----------------------------------------------------------------------------
+ * Call frame, vars, commands structures
+ * ---------------------------------------------------------------------------*/
+
+/* Call frame */
+typedef struct Jim_CallFrame {
+    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
+    struct Jim_HashTable vars; /* Where local vars are stored */
+    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
+    struct Jim_CallFrame *parentCallFrame;
+    Jim_Obj *const *argv; /* object vector of the current procedure call. */
+    int argc; /* number of args of the current procedure call. */
+    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
+    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
+    struct Jim_CallFrame *nextFramePtr;
+} Jim_CallFrame;
+
+/* The var structure. It just holds the pointer of the referenced
+ * object. If linkFramePtr is not NULL the variable is a link
+ * to a variable of name store on objPtr living on the given callframe
+ * (this happens when the [global] or [upvar] command is used).
+ * The interp in order to always know how to free the Jim_Obj associated
+ * with a given variable because In Jim objects memory managment is
+ * bound to interpreters. */
+typedef struct Jim_Var {
+    Jim_Obj *objPtr;
+    struct Jim_CallFrame *linkFramePtr;
+} Jim_Var;
+    
+/* The cmd structure. */
+typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
+    Jim_Obj *const *argv);
+typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
+
+/* A command is implemented in C if funcPtr is != NULL, otherwise
+ * it's a Tcl procedure with the arglist and body represented by the
+ * two objects referenced by arglistObjPtr and bodyoObjPtr. */
+typedef struct Jim_Cmd {
+    Jim_CmdProc cmdProc; /* Not-NULL for a C command. */
+    void *privData; /* Only used for C commands. */
+    Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
+    Jim_Obj *argListObjPtr;
+    Jim_Obj *bodyObjPtr;
+    Jim_HashTable *staticVars; /* Static vars hash table. NULL if no statics. */
+    int arityMin; /* Min number of arguments. */
+    int arityMax; /* Max number of arguments. */
+} Jim_Cmd;
+
+/* Pseudo Random Number Generator State structure */
+typedef struct Jim_PrngState {
+    unsigned char sbox[256];
+    unsigned int i, j;
+} Jim_PrngState;
+
+/* -----------------------------------------------------------------------------
+ * Jim interpreter structure.
+ * Fields similar to the real Tcl interpreter structure have the same names.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Interp {
+    Jim_Obj *result; /* object returned by the last command called. */
+    int errorLine; /* Error line where an error occurred. */
+    const char *errorFileName; /* Error file where an error occurred. */
+    int numLevels; /* Number of current nested calls. */
+    int maxNestingDepth; /* Used for infinite loop detection. */
+    int returnCode; /* Completion code to return on JIM_RETURN. */
+    int exitCode; /* Code to return to the OS on JIM_EXIT. */
+    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
+    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
+    struct Jim_HashTable commands; /* Commands hash table */
+    unsigned jim_wide procEpoch; /* Incremented every time the result
+                of procedures names lookup caching
+                may no longer be valid. */
+    unsigned jim_wide callFrameEpoch; /* Incremented every time a new
+                callframe is created. This id is used for the
+                'ID' field contained in the Jim_CallFrame
+                structure. */
+    Jim_Obj *liveList; /* Linked list of all the live objects. */
+    Jim_Obj *freeList; /* Linked list of all the unused objects. */
+    const char *scriptFileName; /* File name of the script currently in execution. */
+    Jim_Obj *emptyObj; /* Shared empty string object. */
+    unsigned jim_wide referenceNextId; /* Next id for reference. */
+    struct Jim_HashTable references; /* References hash table. */
+    jim_wide lastCollectId; /* reference max Id of the last GC
+                execution. It's set to -1 while the collection
+                is running as sentinel to avoid to recursive
+                calls via the [collect] command inside
+                finalizers. */
+    time_t lastCollectTime; /* unix time of the last GC execution */
+    struct Jim_HashTable sharedStrings; /* Shared Strings hash table */
+    Jim_Obj *stackTrace; /* Stack trace object. */
+    Jim_Obj *unknown; /* Unknown command cache */
+    int errorFlag; /* Set if an error occurred during execution. */
+    int evalRetcodeLevel; /* Level where the last return with code JIM_EVAL
+                             happened. */
+    void *cmdPrivData; /* Used to pass the private data pointer to
+                  a command. It is set to what the user specified
+                  via Jim_CreateCommand(). */
+
+    struct Jim_HashTable stub; /* Stub hash table to export API */
+    /* Jim_GetApi() function pointer, used to bootstrap the STUB table */
+    int (*getApiFuncPtr)(struct Jim_Interp *, const char *, void *);
+    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
+    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
+    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
+    struct Jim_HashTable packages; /* Provided packages hash table */
+    FILE *stdin; /* input file pointer, 'stdin' by default */
+    FILE *stdout; /* output file pointer, 'stdout' by default */
+    FILE *stderr; /* errors file pointer, 'stderr' by default */
+} Jim_Interp;
+
+/* Currently provided as macro that performs the increment.
+ * At some point may be a real function doing more work.
+ * The proc epoch is used in order to know when a command lookup
+ * cached can no longer considered valid. */
+#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+
+/* Note that 'o' is expanded only one time inside this macro,
+ * so it's safe to use side effects. */
+#define Jim_SetResult(i,o) do {     \
+    Jim_Obj *_resultObjPtr_ = (o);    \
+    Jim_IncrRefCount(_resultObjPtr_); \
+    Jim_DecrRefCount(i,(i)->result);  \
+    (i)->result = _resultObjPtr_;     \
+} while(0)
+
+/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+                                  string representation must be fixed length. */
+typedef struct Jim_Reference {
+    Jim_Obj *objPtr;
+    Jim_Obj *finalizerCmdNamePtr;
+    char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+/* -----------------------------------------------------------------------------
+ * Exported API prototypes.
+ * ---------------------------------------------------------------------------*/
+
+/* Macros that are common for extensions and core. */
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+
+/* The core includes real prototypes, extensions instead
+ * include a global function pointer for every function exported.
+ * Once the extension calls Jim_InitExtension(), the global
+ * functon pointers are set to the value of the STUB table
+ * contained in the Jim_Interp structure.
+ *
+ * This makes Jim able to load extensions even if it is statically
+ * linked itself, and to load extensions compiled with different
+ * versions of Jim (as long as the API is still compatible.) */
+
+/* Macros are common for core and extensions */
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#ifndef __JIM_CORE__
+# if defined JIM_EXTENSION || defined JIM_EMBEDDED
+#  define JIM_API(x) (*x)
+#  define JIM_STATIC
+# else
+#  define JIM_API(x) (*x)
+#  define JIM_STATIC extern
+# endif
+#else
+# define JIM_API(x) x
+# define JIM_STATIC static
+#endif /* __JIM_CORE__ */
+
+/* Memory allocation */
+JIM_STATIC void * JIM_API(Jim_Alloc) (int size);
+JIM_STATIC void JIM_API(Jim_Free) (void *ptr);
+JIM_STATIC char * JIM_API(Jim_StrDup) (const char *s);
+
+/* evaluation */
+JIM_STATIC int JIM_API(Jim_Eval)(Jim_Interp *interp, const char *script);
+JIM_STATIC int JIM_API(Jim_EvalGlobal)(Jim_Interp *interp, const char *script);
+JIM_STATIC int JIM_API(Jim_EvalFile)(Jim_Interp *interp, const char *filename);
+JIM_STATIC int JIM_API(Jim_EvalObj) (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_STATIC int JIM_API(Jim_EvalObjBackground) (Jim_Interp *interp,
+        Jim_Obj *scriptObjPtr);
+JIM_STATIC int JIM_API(Jim_EvalObjVector) (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+JIM_STATIC int JIM_API(Jim_SubstObj) (Jim_Interp *interp, Jim_Obj *substObjPtr,
+        Jim_Obj **resObjPtrPtr, int flags);
+
+/* stack */
+JIM_STATIC void JIM_API(Jim_InitStack)(Jim_Stack *stack);
+JIM_STATIC void JIM_API(Jim_FreeStack)(Jim_Stack *stack);
+JIM_STATIC int JIM_API(Jim_StackLen)(Jim_Stack *stack);
+JIM_STATIC void JIM_API(Jim_StackPush)(Jim_Stack *stack, void *element);
+JIM_STATIC void * JIM_API(Jim_StackPop)(Jim_Stack *stack);
+JIM_STATIC void * JIM_API(Jim_StackPeek)(Jim_Stack *stack);
+JIM_STATIC void JIM_API(Jim_FreeStackElements)(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+/* hash table */
+JIM_STATIC int JIM_API(Jim_InitHashTable) (Jim_HashTable *ht,
+        Jim_HashTableType *type, void *privdata);
+JIM_STATIC int JIM_API(Jim_ExpandHashTable) (Jim_HashTable *ht,
+        unsigned int size);
+JIM_STATIC int JIM_API(Jim_AddHashEntry) (Jim_HashTable *ht, const void *key,
+        void *val);
+JIM_STATIC int JIM_API(Jim_ReplaceHashEntry) (Jim_HashTable *ht,
+        const void *key, void *val);
+JIM_STATIC int JIM_API(Jim_DeleteHashEntry) (Jim_HashTable *ht,
+        const void *key);
+JIM_STATIC int JIM_API(Jim_FreeHashTable) (Jim_HashTable *ht);
+JIM_STATIC Jim_HashEntry * JIM_API(Jim_FindHashEntry) (Jim_HashTable *ht,
+        const void *key);
+JIM_STATIC int JIM_API(Jim_ResizeHashTable) (Jim_HashTable *ht);
+JIM_STATIC Jim_HashTableIterator *JIM_API(Jim_GetHashTableIterator)
+        (Jim_HashTable *ht);
+JIM_STATIC Jim_HashEntry * JIM_API(Jim_NextHashEntry)
+        (Jim_HashTableIterator *iter);
+
+/* objects */
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewObj) (Jim_Interp *interp);
+JIM_STATIC void JIM_API(Jim_FreeObj) (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_STATIC void JIM_API(Jim_InvalidateStringRep) (Jim_Obj *objPtr);
+JIM_STATIC void JIM_API(Jim_InitStringRep) (Jim_Obj *objPtr, const char *bytes,
+        int length);
+JIM_STATIC Jim_Obj * JIM_API(Jim_DuplicateObj) (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_STATIC const char * JIM_API(Jim_GetString)(Jim_Obj *objPtr,
+        int *lenPtr);
+JIM_STATIC int JIM_API(Jim_Length)(Jim_Obj *objPtr);
+
+/* string object */
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewStringObj) (Jim_Interp *interp,
+        const char *s, int len);
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewStringObjNoAlloc) (Jim_Interp *interp,
+        char *s, int len);
+JIM_STATIC void JIM_API(Jim_AppendString) (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char *str, int len);
+JIM_STATIC void JIM_API(Jim_AppendObj) (Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *appendObjPtr);
+JIM_STATIC void JIM_API(Jim_AppendStrings) (Jim_Interp *interp,
+        Jim_Obj *objPtr, ...);
+JIM_STATIC int JIM_API(Jim_StringEqObj) (Jim_Obj *aObjPtr,
+        Jim_Obj *bObjPtr, int nocase);
+JIM_STATIC int JIM_API(Jim_StringMatchObj) (Jim_Obj *patternObjPtr,
+        Jim_Obj *objPtr, int nocase);
+JIM_STATIC Jim_Obj * JIM_API(Jim_StringRangeObj) (Jim_Interp *interp,
+        Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+        Jim_Obj *lastObjPtr);
+JIM_STATIC Jim_Obj * JIM_API(Jim_FormatString) (Jim_Interp *interp,
+        Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_STATIC Jim_Obj * JIM_API(Jim_ScanString) (Jim_Interp *interp, Jim_Obj *strObjPtr,
+        Jim_Obj *fmtObjPtr, int flags);
+JIM_STATIC int JIM_API(Jim_CompareStringImmediate) (Jim_Interp *interp,
+        Jim_Obj *objPtr, const char *str);
+
+/* reference object */
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewReference) (Jim_Interp *interp,
+        Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_STATIC Jim_Reference * JIM_API(Jim_GetReference) (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_STATIC int JIM_API(Jim_SetFinalizer) (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_STATIC int JIM_API(Jim_GetFinalizer) (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+/* interpreter */
+JIM_STATIC Jim_Interp * JIM_API(Jim_CreateInterp) (void);
+JIM_STATIC void JIM_API(Jim_FreeInterp) (Jim_Interp *i);
+JIM_STATIC int JIM_API(Jim_GetExitCode) (Jim_Interp *interp);
+JIM_STATIC FILE * JIM_API(Jim_SetStdin) (Jim_Interp *interp, FILE *fp);
+JIM_STATIC FILE * JIM_API(Jim_SetStdout) (Jim_Interp *interp, FILE *fp);
+JIM_STATIC FILE * JIM_API(Jim_SetStderr) (Jim_Interp *interp, FILE *fp);
+
+/* commands */
+JIM_STATIC void JIM_API(Jim_RegisterCoreCommands) (Jim_Interp *interp);
+JIM_STATIC int JIM_API(Jim_CreateCommand) (Jim_Interp *interp, 
+        const char *cmdName, Jim_CmdProc cmdProc, void *privData,
+         Jim_DelCmdProc delProc);
+JIM_STATIC int JIM_API(Jim_CreateProcedure) (Jim_Interp *interp, 
+        const char *cmdName, Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr,
+        Jim_Obj *bodyObjPtr, int arityMin, int arityMax);
+JIM_STATIC int JIM_API(Jim_DeleteCommand) (Jim_Interp *interp,
+        const char *cmdName);
+JIM_STATIC int JIM_API(Jim_RenameCommand) (Jim_Interp *interp, 
+        const char *oldName, const char *newName);
+JIM_STATIC Jim_Cmd * JIM_API(Jim_GetCommand) (Jim_Interp *interp,
+        Jim_Obj *objPtr, int flags);
+JIM_STATIC int JIM_API(Jim_SetVariable) (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_STATIC int JIM_API(Jim_SetVariableStr) (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_STATIC int JIM_API(Jim_SetGlobalVariableStr) (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_STATIC int JIM_API(Jim_SetVariableStrWithStr) (Jim_Interp *interp,
+        const char *name, const char *val);
+JIM_STATIC int JIM_API(Jim_SetVariableLink) (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+        Jim_CallFrame *targetCallFrame);
+JIM_STATIC Jim_Obj * JIM_API(Jim_GetVariable) (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_STATIC Jim_Obj * JIM_API(Jim_GetGlobalVariable) (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_STATIC Jim_Obj * JIM_API(Jim_GetVariableStr) (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_STATIC Jim_Obj * JIM_API(Jim_GetGlobalVariableStr) (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_STATIC int JIM_API(Jim_UnsetVariable) (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+
+/* call frame */
+JIM_STATIC int JIM_API(Jim_GetCallFrameByLevel) (Jim_Interp *interp,
+        Jim_Obj *levelObjPtr, Jim_CallFrame **framePtrPtr,
+        int *newLevelPtr);
+
+/* garbage collection */
+JIM_STATIC int JIM_API(Jim_Collect) (Jim_Interp *interp);
+JIM_STATIC void JIM_API(Jim_CollectIfNeeded) (Jim_Interp *interp);
+
+/* index object */
+JIM_STATIC int JIM_API(Jim_GetIndex) (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *indexPtr);
+
+/* list object */
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewListObj) (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_STATIC void JIM_API(Jim_ListInsertElements) (Jim_Interp *interp,
+        Jim_Obj *listPtr, int index, int objc, Jim_Obj *const *objVec);
+JIM_STATIC void JIM_API(Jim_ListAppendElement) (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_STATIC void JIM_API(Jim_ListAppendList) (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_STATIC void JIM_API(Jim_ListLength) (Jim_Interp *interp, Jim_Obj *listPtr,
+        int *intPtr);
+JIM_STATIC int JIM_API(Jim_ListIndex) (Jim_Interp *interp, Jim_Obj *listPrt,
+        int index, Jim_Obj **objPtrPtr, int seterr);
+JIM_STATIC int JIM_API(Jim_SetListIndex) (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+        Jim_Obj *newObjPtr);
+JIM_STATIC Jim_Obj * JIM_API(Jim_ConcatObj) (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+
+/* dict object */
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewDictObj) (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_STATIC int JIM_API(Jim_DictKey) (Jim_Interp *interp, Jim_Obj *dictPtr,
+        Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_STATIC int JIM_API(Jim_DictKeysVector) (Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj **objPtrPtr, int flags);
+JIM_STATIC int JIM_API(Jim_SetDictKeysVector) (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj *newObjPtr);
+
+/* return code object */
+JIM_STATIC int JIM_API(Jim_GetReturnCode) (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *intPtr);
+
+/* expression object */
+JIM_STATIC int JIM_API(Jim_EvalExpression) (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
+JIM_STATIC int JIM_API(Jim_GetBoolFromExpr) (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, int *boolPtr);
+
+/* integer object */
+JIM_STATIC int JIM_API(Jim_GetWide) (Jim_Interp *interp, Jim_Obj *objPtr,
+        jim_wide *widePtr);
+JIM_STATIC int JIM_API(Jim_GetLong) (Jim_Interp *interp, Jim_Obj *objPtr,
+        long *longPtr);
+JIM_STATIC void JIM_API(Jim_SetWide) (Jim_Interp *interp, Jim_Obj *objPtr,
+        jim_wide wideValue);
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewIntObj) (Jim_Interp *interp,
+        jim_wide wideValue);
+
+/* double object */
+JIM_STATIC int JIM_API(Jim_GetDouble)(Jim_Interp *interp, Jim_Obj *objPtr,
+        double *doublePtr);
+JIM_STATIC void JIM_API(Jim_SetDouble)(Jim_Interp *interp, Jim_Obj *objPtr,
+        double doubleValue);
+JIM_STATIC Jim_Obj * JIM_API(Jim_NewDoubleObj)(Jim_Interp *interp, double doubleValue);
+
+/* shared strings */
+JIM_STATIC const char * JIM_API(Jim_GetSharedString) (Jim_Interp *interp, 
+        const char *str);
+JIM_STATIC void JIM_API(Jim_ReleaseSharedString) (Jim_Interp *interp,
+        const char *str);
+
+/* commands utilities */
+JIM_STATIC void JIM_API(Jim_WrongNumArgs) (Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv, const char *msg);
+JIM_STATIC int JIM_API(Jim_GetEnum) (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char **tablePtr, int *indexPtr, const char *name, int flags);
+JIM_STATIC int JIM_API(Jim_ScriptIsComplete) (const char *s, int len,
+        char *stateCharPtr);
+
+/* package utilities */
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_STATIC void * JIM_API(Jim_GetAssocData)(Jim_Interp *interp, const char *key);
+JIM_STATIC int JIM_API(Jim_SetAssocData)(Jim_Interp *interp, const char *key,
+        Jim_InterpDeleteProc *delProc, void *data);
+JIM_STATIC int JIM_API(Jim_DeleteAssocData)(Jim_Interp *interp, const char *key);
+
+/* API import/export functions */
+JIM_STATIC int JIM_API(Jim_GetApi) (Jim_Interp *interp, const char *funcname,
+        void *targetPtrPtr);
+JIM_STATIC int JIM_API(Jim_RegisterApi) (Jim_Interp *interp, 
+        const char *funcname, void *funcptr);
+
+/* Packages C API */
+JIM_STATIC int JIM_API(Jim_PackageProvide) (Jim_Interp *interp,
+        const char *name, const char *ver, int flags);
+JIM_STATIC const char * JIM_API(Jim_PackageRequire) (Jim_Interp *interp,
+        const char *name, const char *ver, int flags);
+
+/* error messages */
+JIM_STATIC void JIM_API(Jim_PrintErrorMessage) (Jim_Interp *interp);
+
+/* interactive mode */
+JIM_STATIC int JIM_API(Jim_InteractivePrompt) (Jim_Interp *interp);
+
+/* Misc */
+JIM_STATIC void JIM_API(Jim_Panic) (Jim_Interp *interp, const char *fmt, ...);
+
+#undef JIM_STATIC
+#undef JIM_API
+
+#ifndef __JIM_CORE__
+
+#define JIM_GET_API(name) \
+    Jim_GetApi(interp, "Jim_" #name, ((void *)&Jim_ ## name))
+
+#if defined JIM_EXTENSION || defined JIM_EMBEDDED
+/* This must be included "inline" inside the extension */
+static void Jim_InitExtension(Jim_Interp *interp)
+{
+  Jim_GetApi = interp->getApiFuncPtr;
+
+  JIM_GET_API(Alloc);
+  JIM_GET_API(Free);
+  JIM_GET_API(Eval);
+  JIM_GET_API(EvalGlobal);
+  JIM_GET_API(EvalFile);
+  JIM_GET_API(EvalObj);
+  JIM_GET_API(EvalObjBackground);
+  JIM_GET_API(EvalObjVector);
+  JIM_GET_API(InitHashTable);
+  JIM_GET_API(ExpandHashTable);
+  JIM_GET_API(AddHashEntry);
+  JIM_GET_API(ReplaceHashEntry);
+  JIM_GET_API(DeleteHashEntry);
+  JIM_GET_API(FreeHashTable);
+  JIM_GET_API(FindHashEntry);
+  JIM_GET_API(ResizeHashTable);
+  JIM_GET_API(GetHashTableIterator);
+  JIM_GET_API(NextHashEntry);
+  JIM_GET_API(NewObj);
+  JIM_GET_API(FreeObj);
+  JIM_GET_API(InvalidateStringRep);
+  JIM_GET_API(InitStringRep);
+  JIM_GET_API(DuplicateObj);
+  JIM_GET_API(GetString);
+  JIM_GET_API(Length);
+  JIM_GET_API(InvalidateStringRep);
+  JIM_GET_API(NewStringObj);
+  JIM_GET_API(NewStringObjNoAlloc);
+  JIM_GET_API(AppendString);
+  JIM_GET_API(AppendObj);
+  JIM_GET_API(AppendStrings);
+  JIM_GET_API(StringEqObj);
+  JIM_GET_API(StringMatchObj);
+  JIM_GET_API(StringRangeObj);
+  JIM_GET_API(FormatString);
+  JIM_GET_API(ScanString);
+  JIM_GET_API(CompareStringImmediate);
+  JIM_GET_API(NewReference);
+  JIM_GET_API(GetReference);
+  JIM_GET_API(SetFinalizer);
+  JIM_GET_API(GetFinalizer);
+  JIM_GET_API(CreateInterp);
+  JIM_GET_API(FreeInterp);
+  JIM_GET_API(GetExitCode);
+  JIM_GET_API(SetStdin);
+  JIM_GET_API(SetStdout);
+  JIM_GET_API(SetStderr);
+  JIM_GET_API(CreateCommand);
+  JIM_GET_API(CreateProcedure);
+  JIM_GET_API(DeleteCommand);
+  JIM_GET_API(RenameCommand);
+  JIM_GET_API(GetCommand);
+  JIM_GET_API(SetVariable);
+  JIM_GET_API(SetVariableStr);
+  JIM_GET_API(SetGlobalVariableStr);
+  JIM_GET_API(SetVariableStrWithStr);
+  JIM_GET_API(SetVariableLink);
+  JIM_GET_API(GetVariable);
+  JIM_GET_API(GetCallFrameByLevel);
+  JIM_GET_API(Collect);
+  JIM_GET_API(CollectIfNeeded);
+  JIM_GET_API(GetIndex);
+  JIM_GET_API(NewListObj);
+  JIM_GET_API(ListInsertElements);
+  JIM_GET_API(ListAppendElement);
+  JIM_GET_API(ListAppendList);
+  JIM_GET_API(ListLength);
+  JIM_GET_API(ListIndex);
+  JIM_GET_API(SetListIndex);
+  JIM_GET_API(ConcatObj);
+  JIM_GET_API(NewDictObj);
+  JIM_GET_API(DictKey);
+  JIM_GET_API(DictKeysVector);
+  JIM_GET_API(GetIndex);
+  JIM_GET_API(GetReturnCode);
+  JIM_GET_API(EvalExpression);
+  JIM_GET_API(GetBoolFromExpr);
+  JIM_GET_API(GetWide);
+  JIM_GET_API(GetLong);
+  JIM_GET_API(SetWide);
+  JIM_GET_API(NewIntObj);
+  JIM_GET_API(GetDouble);
+  JIM_GET_API(SetDouble);
+  JIM_GET_API(NewDoubleObj);
+  JIM_GET_API(WrongNumArgs);
+  JIM_GET_API(SetDictKeysVector);
+  JIM_GET_API(SubstObj);
+  JIM_GET_API(RegisterApi);
+  JIM_GET_API(PrintErrorMessage);
+  JIM_GET_API(InteractivePrompt);
+  JIM_GET_API(RegisterCoreCommands);
+  JIM_GET_API(GetSharedString);
+  JIM_GET_API(ReleaseSharedString);
+  JIM_GET_API(Panic);
+  JIM_GET_API(StrDup);
+  JIM_GET_API(UnsetVariable);
+  JIM_GET_API(GetVariableStr);
+  JIM_GET_API(GetGlobalVariable);
+  JIM_GET_API(GetGlobalVariableStr);
+  JIM_GET_API(GetAssocData);
+  JIM_GET_API(SetAssocData);
+  JIM_GET_API(DeleteAssocData);
+  JIM_GET_API(GetEnum);
+  JIM_GET_API(ScriptIsComplete);
+  JIM_GET_API(PackageProvide);
+  JIM_GET_API(PackageRequire);
+  JIM_GET_API(InitStack);
+  JIM_GET_API(FreeStack);
+  JIM_GET_API(StackLen);
+  JIM_GET_API(StackPush);
+  JIM_GET_API(StackPop);
+  JIM_GET_API(StackPeek);
+  JIM_GET_API(FreeStackElements);
+}
+#endif /* defined JIM_EXTENSION || defined JIM_EMBEDDED */
+
+#undef JIM_GET_API
+
+#ifdef JIM_EMBEDDED
+Jim_Interp *ExportedJimCreateInterp(void);
+static void Jim_InitEmbedded(void) {
+    Jim_Interp *i = ExportedJimCreateInterp();
+    Jim_InitExtension(i);
+    Jim_FreeInterp(i);
+}
+#endif /* JIM_EMBEDDED */
+#endif /* __JIM_CORE__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JIM__H */
diff --git a/packages/net/athttpd/v2_0/include/md5.h b/packages/net/athttpd/v2_0/include/md5.h
new file mode 100644 (file)
index 0000000..adadc0d
--- /dev/null
@@ -0,0 +1,37 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+#include <cyg/athttpd/global.h>
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, unsigned char*, unsigned int);
+void MD5Final(unsigned char [16], MD5_CTX *);
+
diff --git a/packages/net/athttpd/v2_0/include/socket.h b/packages/net/athttpd/v2_0/include/socket.h
new file mode 100644 (file)
index 0000000..a9646a8
--- /dev/null
@@ -0,0 +1,76 @@
+/* =================================================================
+ *
+ *      socket.h
+ *
+ *      Improved HTTPD server.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#ifndef __SOCKET_H__
+#define __SOCKET_H__
+
+#include <pkgconf/system.h>
+
+#define CYG_HTTPD_SOCKET_IDLE_TIMEOUT          300 // In seconds
+
+extern cyg_thread   cyg_httpd_thread_object;
+extern cyg_handle_t cyg_httpd_thread_handle;
+extern cyg_uint8    cyg_httpd_thread_stack[];
+
+
+void cyg_httpd_daemon(cyg_addrword_t);
+void cyg_httpd_start(void);
+ssize_t cyg_httpd_write(char*, int);
+ssize_t cyg_httpd_start_chunked(char*);
+ssize_t cyg_httpd_write_chunked(char*, int);
+void cyg_httpd_end_chunked(void);
+cyg_int32 cyg_httpd_socket_setup(void);
+cyg_int32 cyg_httpd_socket_handle_request(void);
+ssize_t cyg_httpd_writev(cyg_iovec*, int );
+#endif
diff --git a/packages/net/athttpd/v2_0/src/auth.c b/packages/net/athttpd/v2_0/src/auth.c
new file mode 100644 (file)
index 0000000..2a4a9fa
--- /dev/null
@@ -0,0 +1,445 @@
+/* =================================================================
+ *
+ *      auth.c
+ *
+ *      Handles basic authentication.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <cyg/kernel/kapi.h>           // Kernel API.
+#include <cyg/hal/hal_tables.h>
+
+#include <stdio.h>
+
+#include <network.h>
+#include <string.h>
+
+#include <cyg/athttpd/http.h>
+#include <cyg/athttpd/md5.h>
+
+// This is a string that contains the domain that is currently authorized.
+cyg_uint8 *cyg_httpd_current_authName;
+
+CYG_HAL_TABLE_BEGIN(cyg_httpd_auth_table, httpd_auth_table );
+CYG_HAL_TABLE_END(cyg_httpd_auth_table_end, httpd_auth_table );
+
+__externC cyg_httpd_auth_table_entry cyg_httpd_auth_table[];
+__externC cyg_httpd_auth_table_entry cyg_httpd_auth_table_end[];
+
+// Variables used for authorization. The header parsing code will only copy
+//  up to AUTH_STORAGE_BUFFER_LENGTH bytes into cyg_httpd_md5_response to
+//  avoid overflow.
+char cyg_httpd_md5_response[AUTH_STORAGE_BUFFER_LENGTH + 1];
+char cyg_httpd_md5_digest[AUTH_STORAGE_BUFFER_LENGTH + 1];
+char cyg_httpd_md5_nonce[33];
+char cyg_httpd_md5_cnonce[33];
+char cyg_httpd_md5_noncecount[9];
+char cyg_httpd_md5_ha2[HASHHEXLEN+1] = {'\0'};
+char cyg_httpd_md5_ha1[HASHHEXLEN+1];
+
+char b64string[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+cyg_httpd_auth_table_entry*
+cyg_httpd_auth_entry_from_path(char *authPath)
+{
+    cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table;
+    if (strcmp(authPath, "/") != 0)
+        while (entry != cyg_httpd_auth_table_end)
+        {
+            if (strncmp(entry->auth_dirname,
+                        authPath,
+                        strlen(entry->auth_dirname)) == 0)
+                return entry;
+            entry++;
+        }
+    else
+        while (entry != cyg_httpd_auth_table_end)
+        {
+            if (strcmp(entry->auth_dirname, authPath) == 0)
+                return entry;
+            entry++;
+        }
+            
+    return (cyg_httpd_auth_table_entry *)0;
+}
+
+cyg_httpd_auth_table_entry*
+cyg_httpd_auth_entry_from_domain(char *authDomain)
+{
+    cyg_httpd_auth_table_entry *entry = cyg_httpd_auth_table;
+    while (entry != cyg_httpd_auth_table_end)
+    {
+        if (!strncmp((const char*)authDomain, 
+                       entry->auth_domainname,
+                       strlen(entry->auth_domainname)))
+            return entry;
+        entry++;
+    }
+            
+    return (cyg_httpd_auth_table_entry *)0;
+}
+
+static cyg_int32
+cyg_httpd_base64_decode(char* to, char* from, cyg_uint32 len )
+{
+    char     *fromp = from;
+    char     *top = to;
+    char     *p;
+    char      cbyte;
+    char      obyte;
+    cyg_int32 padding = 0;
+
+    for (; len >= 4; len -= 4)
+    {
+        if ((cbyte = *fromp++) == '=')
+            cbyte = 0;
+        else
+        {
+            if (badchar(cbyte, p ) )
+                return -1;
+            cbyte = (p - b64string);
+        }
+        obyte = cbyte << 2;
+
+        if ((cbyte = *fromp++) == '=')
+            cbyte = 0;
+        else
+        {
+            if (badchar(cbyte, p))
+                return -1;
+            cbyte = p - b64string;
+        }
+        obyte |= cbyte >> 4;
+        *top++ = obyte;
+
+        obyte = cbyte << 4;
+        if ((cbyte = *fromp++) == '=')
+        {
+            cbyte = 0; 
+            padding++;
+        }
+        else
+        {
+            padding = 0;
+            if (badchar(cbyte, p))
+                return -1;
+            cbyte = p - b64string;
+        }
+        obyte |= cbyte >> 2;
+        *top++ = obyte;
+
+        obyte = cbyte << 6;
+        if ((cbyte = *fromp++) == '=')
+        {
+            cbyte = 0;
+            padding++;
+        }
+        else
+        {
+            padding = 0;
+            if (badchar(cbyte, p))
+                return -1;
+            cbyte = p - b64string;
+        }
+        obyte |= cbyte;
+        *top++ = obyte;
+    }
+
+    *top = 0;
+    if (len)
+        return -1;
+    return (top - to) - padding;
+}
+
+// The following code is a slightly modified version of those available at the
+//  end of RFC1270.
+static void cyg_httpd_cvthex(HASH Bin, HASHHEX Hex)
+{
+    unsigned short i;
+    unsigned char j;
+
+    for (i = 0; i < HASHLEN; i++)
+    {
+        j = (Bin[i] >> 4) & 0xf;
+        if (j <= 9)
+            Hex[i*2] = (j + '0');
+         else
+            Hex[i*2] = (j + 'a' - 10);
+        j = Bin[i] & 0xf;
+        if (j <= 9)
+            Hex[i*2+1] = (j + '0');
+         else
+            Hex[i*2+1] = (j + 'a' - 10);
+    };
+    Hex[HASHHEXLEN] = '\0';
+};
+
+// Calculate H(A1) as per spec.
+static void
+cyg_httpd_digest_calc_HA1( char    *pszAlg,
+                           char    *pszUserName,
+                           char    *pszRealm,
+                           char    *pszPassword,
+                           char    *pszNonce,
+                           char    *pszCNonce,
+                           HASHHEX  SessionKey )
+{
+      MD5_CTX Md5Ctx;
+      HASH HA1;
+
+      MD5Init(&Md5Ctx);
+      MD5Update(&Md5Ctx, (unsigned char*)pszUserName, strlen(pszUserName));
+      MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+      MD5Update(&Md5Ctx, (unsigned char*)pszRealm, strlen(pszRealm));
+      MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+      MD5Update(&Md5Ctx, (unsigned char*)pszPassword, strlen(pszPassword));
+      MD5Final((unsigned char*)HA1, &Md5Ctx);
+      if (strcmp(pszAlg, "md5-sess") == 0) 
+      {
+          MD5Init(&Md5Ctx);
+          MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHLEN);
+          MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+          MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce));
+          MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+          MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce));
+          MD5Final((unsigned char*)HA1, &Md5Ctx);
+      };
+      cyg_httpd_cvthex(HA1, SessionKey);
+};
+
+// Calculate request-digest/response-digest as per HTTP Digest spec.
+void
+cyg_httpd_digest_calc_response(HASHHEX  HA1,           
+                               char    *pszNonce,       
+                               char    *pszNonceCount,  
+                               char    *pszCNonce,      
+                               char    *pszQop,         
+                               char    *pszMethod,      
+                               char    *pszDigestUri,   
+                               HASHHEX  HEntity,       
+                               HASHHEX  Response)
+{
+    MD5_CTX Md5Ctx;
+    HASH HA2;
+    HASH RespHash;
+    HASHHEX HA2Hex;
+
+    // Calculate H(A2).
+    MD5Init(&Md5Ctx);
+    MD5Update(&Md5Ctx, (unsigned char*)pszMethod, strlen(pszMethod));
+    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+    MD5Update(&Md5Ctx, (unsigned char*)pszDigestUri, strlen(pszDigestUri));
+    if (strcmp(pszQop, "auth-int") == 0) {
+        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+        MD5Update(&Md5Ctx, (unsigned char*)HEntity, HASHHEXLEN);
+    };
+    MD5Final((unsigned char*)HA2, &Md5Ctx);
+    cyg_httpd_cvthex(HA2, HA2Hex);
+
+    // calculate response
+    MD5Init(&Md5Ctx);
+    MD5Update(&Md5Ctx, (unsigned char*)HA1, HASHHEXLEN);
+    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+    MD5Update(&Md5Ctx, (unsigned char*)pszNonce, strlen(pszNonce));
+    MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+    if (*pszQop) 
+    {
+        MD5Update(&Md5Ctx, (unsigned char*)pszNonceCount, strlen(pszNonceCount));
+        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+        MD5Update(&Md5Ctx, (unsigned char*)pszCNonce, strlen(pszCNonce));
+        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+        MD5Update(&Md5Ctx, (unsigned char*)pszQop, strlen(pszQop));
+        MD5Update(&Md5Ctx, (unsigned char*)":", 1);
+    };
+    MD5Update(&Md5Ctx, (unsigned char*)HA2Hex, HASHHEXLEN);
+    MD5Final((unsigned char*)RespHash, &Md5Ctx);
+    cyg_httpd_cvthex(RespHash, Response);
+};
+
+cyg_httpd_auth_table_entry*
+cyg_httpd_is_authenticated(char* fname)
+{
+    // Let's check if the directory access needs authorization. The 
+    //  authentication is done on the directory name.
+    cyg_httpd_auth_table_entry* entry =
+                                cyg_httpd_auth_entry_from_path(fname);
+    if (entry != 0)
+    {
+        if (entry->auth_mode == CYG_HTTPD_AUTH_BASIC)
+        {
+            cyg_httpd_base64_decode(cyg_httpd_md5_digest,
+                                    cyg_httpd_md5_response,
+                                    strlen(cyg_httpd_md5_response));
+            char *colon = rindex(cyg_httpd_md5_digest, ':');
+            if (colon == NULL)
+            {
+                return (httpstate.needs_auth = entry);
+            }    
+            else
+            {    
+                *colon = '\0'; // Crypto now has the username.
+                
+                // In the case of a 'Basic" authentication, the HTTP header
+                //  did not return to us the domain name that we sent when we
+                //  challenged the request: The only things that are returned 
+                //  are the username:password duo. In this case I will just 
+                //  compare the entry's username/password to those read from 
+                //  the header.
+                if ((strcmp(entry->auth_username,cyg_httpd_md5_digest) != 0) ||
+                                 (strcmp(entry->auth_password, ++colon) != 0))
+                    return (httpstate.needs_auth = entry);
+            }    
+        }
+        else
+        {
+            char *cyg_httpd_md5_method;
+            
+            switch (httpstate.method)
+            {
+            case CYG_HTTPD_METHOD_GET:
+                cyg_httpd_md5_method = "GET";
+                break;
+            case CYG_HTTPD_METHOD_POST:
+                cyg_httpd_md5_method = "POST";
+                break;
+            default:
+                cyg_httpd_md5_method = "HEAD";
+                break;
+            }    
+            cyg_httpd_digest_calc_HA1(CYG_HTTPD_MD5_AUTH_NAME,
+                                      entry->auth_username,
+                                      entry->auth_domainname,
+                                      entry->auth_password,
+                                      cyg_httpd_md5_nonce,
+                                      cyg_httpd_md5_cnonce,
+                                      cyg_httpd_md5_ha1);
+            cyg_httpd_digest_calc_response(cyg_httpd_md5_ha1,
+                                           cyg_httpd_md5_nonce,
+                                           cyg_httpd_md5_noncecount,
+                                           cyg_httpd_md5_cnonce,
+                                           CYG_HTTPD_MD5_AUTH_QOP,
+                                           cyg_httpd_md5_method,
+                                           httpstate.url,
+                                           cyg_httpd_md5_ha2,
+                                           cyg_httpd_md5_digest);
+            if (strcmp(cyg_httpd_md5_response, cyg_httpd_md5_digest) != 0)
+                return (httpstate.needs_auth = entry);
+        }
+    }
+    // No need for authentication...
+    return (cyg_httpd_auth_table_entry*)0;
+}
+
+char*
+cyg_httpd_digest_data(char *dest, char *src)
+{
+    int exit = 0;
+    while (exit == 0)
+    {
+        switch (*src )
+        {
+        case '\r':
+        case '\n':
+            *dest = '\0';
+            exit = 1;
+            break;
+        case ',':
+            // If it is a comma there might or might not be a blank space
+            //  following it (IE7 inserts no spaces, everyone else does...)
+            //  so before exiting the loop remove any blank space that follows.
+            if (src[1] == ' ')
+                src++;             
+        case ' ':
+            src++;
+            *dest = '\0';
+            exit = 1;
+            break;
+        case '"':
+            src++;
+            break;
+        default:
+            *dest++ = *src++;
+        }    
+    }
+    return src;
+}    
+
+// Skips through fields we do not need.
+char*
+cyg_httpd_digest_skip(char *p)
+{
+    if (*p == '"')
+    {
+        p++;
+        while ((*p != '"') && (*p != '\n'))
+            p++;
+        p++;
+        if (*p == ',')
+            p++;
+        if (*p == ' ')
+            p++;
+        if (*p == '\n')
+            p++;
+    }
+    else        
+    {    
+        while ((*p != ' ') && (*p != '\n'))
+            p++;
+        if (*p == ',')
+            p++;
+        if (*p == ' ')
+            p++;
+        if (*p == '\n')
+            p++;
+    }        
+    return p;
+}
diff --git a/packages/net/athttpd/v2_0/src/cgi.c b/packages/net/athttpd/v2_0/src/cgi.c
new file mode 100644 (file)
index 0000000..5c4800b
--- /dev/null
@@ -0,0 +1,292 @@
+/* =================================================================
+ *
+ *      cgi.c
+ *
+ *      Handles the CGI requests via OBJLOADER or tcl
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <cyg/hal/hal_tables.h>
+#include <cyg/fileio/fileio.h>
+#include <dirent.h>
+#include <network.h>
+
+#include <string.h>
+#include <stdio.h>                     // sprintf().
+
+#define JIM_EMBEDDED
+#include <cyg/athttpd/http.h>
+#include <cyg/athttpd/socket.h>
+#include <cyg/athttpd/handler.h>
+#include <cyg/athttpd/forms.h>
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+#include <cyg/objloader/elf.h>
+#include <cyg/objloader/objelf.h>
+#endif
+
+// =============================================================================
+// Objloader CGI Support
+// =============================================================================
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+CYG_LDR_TABLE_STDIO()
+CYG_LDR_TABLE_STRING()
+
+// Chunked transfers.
+CYG_LDR_TABLE_ENTRY(cyg_httpd_start_chunked_entry,      \
+                    "cyg_httpd_start_chunked",          \
+                    cyg_httpd_start_chunked);
+CYG_LDR_TABLE_ENTRY(cyg_httpd_write_chunked_entry,      \
+                    "cyg_httpd_write_chunked",          \
+                    cyg_httpd_write_chunked);
+CYG_LDR_TABLE_ENTRY(cyg_httpd_end_chunked_entry,      \
+                    "cyg_httpd_end_chunked",          \
+                    cyg_httpd_end_chunked);
+
+// Mime strings.
+CYG_LDR_TABLE_ENTRY(cyg_httpd_write_entry, \
+                    "cyg_httpd_write",     \
+                    cyg_httpd_write);
+                     
+// Entry to find a GET/POST variable in the table.                     
+CYG_LDR_TABLE_ENTRY(cyg_httpd_find_form_variable_entry, \
+                    "cyg_httpd_find_form_variable",     \
+                    cyg_httpd_find_form_variable);
+
+// Finds an internal resource given the URL. Returns a pointer to the entry
+//  in the resource table.
+CYG_LDR_TABLE_ENTRY(cyg_httpd_find_ires_entry, \
+                    "cyg_httpd_find_ires",     \
+                    cyg_httpd_find_ires);
+// Sends an internal resource out, given the entry in the reource table.
+CYG_LDR_TABLE_ENTRY(cyg_httpd_send_ires_entry, \
+                    "cyg_httpd_send_ires",     \
+                    cyg_httpd_send_ires);
+                     
+CYG_LDR_TABLE_ENTRY(cyg_httpd_format_header_entry, \
+                    "cyg_httpd_format_header",     \
+                    cyg_httpd_format_header);
+CYG_LDR_TABLE_ENTRY(diag_printf_entry, "diag_printf", diag_printf);
+CYG_LDR_TABLE_ENTRY(cyg_httpd_find_mime_string_entry, \
+                    "cyg_httpd_find_mime_string",     \
+                    cyg_httpd_find_mime_string);
+#endif // CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+cyg_int32 cyg_httpd_exec_cgi_objloader(char *file_name)
+{
+    // Check if the file is in the file system.
+    struct stat sp;
+    cyg_int32 (*fn)(CYG_HTTPD_STATE*);
+    
+    cyg_int32 rc = stat(file_name, &sp);
+    if(rc < 0)
+    {
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
+        return 0;
+    }    
+    
+    void *lib_handle = cyg_ldr_open_library((CYG_ADDRWORD)file_name, 0);
+    CYG_ASSERT(lib_handle != 0, "Error opening the library");
+    if (lib_handle == 0)
+    {
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+        return 0;
+    }    
+    fn = cyg_ldr_find_symbol(lib_handle, "exec_cgi");
+    if (fn)
+    {
+        cyg_int32 rc = fn(&httpstate);
+        cyg_ldr_close_library(lib_handle);
+        return rc;
+    }    
+    else
+    {
+        cyg_ldr_close_library(lib_handle);
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+        return 0;
+    }    
+}
+#endif
+
+// =============================================================================
+// tcl CGI Support
+// =============================================================================
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
+int Jim_AioInit(Jim_Interp *);
+cyg_int32
+cyg_httpd_exec_cgi_tcl(char *file_name)
+{
+    // Make sure that tcl sees the internal variables including the post_data.
+    cyg_httpd_fvars_table_entry *entry = cyg_httpd_fvars_table;
+    while (entry != cyg_httpd_fvars_table_end)
+    {
+        if (strlen(entry->buf) != 0)
+            Jim_SetVariableStrWithStr(httpstate.jim_interp, 
+                                      entry->name, 
+                                      entry->buf);
+        entry++;
+    }
+
+    if (httpstate.post_data != NULL)
+        Jim_SetVariableStrWithStr(httpstate.jim_interp, 
+                                  "post_data", 
+                                  httpstate.post_data);
+     
+    char tcl_cmd[CYG_HTTPD_MAXPATH];
+    sprintf(tcl_cmd, "source %s", file_name);
+    Jim_Eval(httpstate.jim_interp, tcl_cmd);
+    return 0;
+}
+
+int
+cyg_httpd_Jim_Command_startchunked(Jim_Interp *interp, 
+                                   int argc,
+                                   Jim_Obj *const *argv)
+{
+    char *buf = (char*)Jim_GetString(argv[1], NULL);
+    cyg_httpd_start_chunked(buf);
+    return JIM_OK;
+}
+  
+int
+cyg_httpd_Jim_Command_writechunked(Jim_Interp *interp, 
+                                   int argc,
+                                   Jim_Obj *const *argv)
+{
+    int len;
+    char *buf = (char*)Jim_GetString(argv[1], &len);
+    cyg_httpd_write_chunked(buf, len);
+    return JIM_OK;
+}
+  
+int
+cyg_httpd_Jim_Command_endchunked(Jim_Interp *interp, 
+                                 int argc,
+                                 Jim_Obj *const *argv)
+{
+    cyg_httpd_end_chunked();
+    return JIM_OK;
+}
+  
+void
+cyg_httpd_init_tcl_interpreter(void)
+{
+    // Start the TCL interpreter.
+    Jim_InitEmbedded();
+    httpstate.jim_interp = Jim_CreateInterp();
+    Jim_RegisterCoreCommands(httpstate.jim_interp);
+    Jim_AioInit(httpstate.jim_interp);
+    
+    // Add a new cyg_httpd_write_chunked command for tcl.
+    Jim_CreateCommand(httpstate.jim_interp,
+                      "start_chunked",
+                      cyg_httpd_Jim_Command_startchunked,
+                      NULL, 
+                      NULL);
+    Jim_CreateCommand(httpstate.jim_interp,
+                      "write_chunked",
+                      cyg_httpd_Jim_Command_writechunked,
+                      NULL, 
+                      NULL);
+    Jim_CreateCommand(httpstate.jim_interp,
+                      "end_chunked",
+                      cyg_httpd_Jim_Command_endchunked,
+                      NULL, 
+                      NULL);
+}                      
+#endif    
+
+// =============================================================================
+// CGI Support
+// =============================================================================
+#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL ) || \
+    defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER)
+cyg_int32 
+cyg_httpd_exec_cgi(void)
+{
+    char  file_name[CYG_HTTPD_MAXPATH];
+    
+    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
+    if (file_name[strlen(file_name)-1] != '/')
+        strcat(file_name, "/");
+    strcat(file_name, httpstate.url);
+    cyg_httpd_cleanup_filename(file_name);
+    
+    char *extension = rindex(httpstate.url, '.');
+    if (extension == NULL)
+    {
+        // File in CGI request _must_ have an extension.
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+        return 0;
+    }    
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+    if (strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_OBJLOADER_EXTENSION) == 0)
+    {
+        // Load a cgibin via OBJLOADER.
+        cyg_int32 rc = cyg_httpd_exec_cgi_objloader(file_name);
+        return rc;
+    }    
+#endif
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
+    if (strcmp(extension, CYG_HTTPD_DEFAULT_CGIBIN_TCL_EXTENSION) == 0)
+    {
+        // Load a cgibin via the TCL interpreter.
+        cyg_int32 rc = cyg_httpd_exec_cgi_tcl(file_name);
+        return rc;
+    }    
+#endif
+    cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+    return 0;
+}
+#endif 
+
diff --git a/packages/net/athttpd/v2_0/src/forms.c b/packages/net/athttpd/v2_0/src/forms.c
new file mode 100644 (file)
index 0000000..e530a8f
--- /dev/null
@@ -0,0 +1,309 @@
+/* =================================================================
+ *
+ *      forms.c
+ *
+ *      Handles form variables of GET and POST requests.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
+ *                Lars Povlsen    (lpovlsen@vitesse.com)
+ *                Tad Artis       (ecos@ds3switch.com)
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+#include <cyg/kernel/kapi.h>           // Kernel API.
+#include <cyg/kernel/ktypes.h>         // base kernel types.
+#include <cyg/infra/diag.h>            // For diagnostic printing.
+#include <network.h>
+#include <sys/uio.h>
+
+#include <cyg/hal/hal_tables.h>
+#include <stdlib.h>
+
+#include <cyg/athttpd/http.h>
+#include <cyg/athttpd/socket.h>
+#include <cyg/athttpd/handler.h>
+#include <cyg/athttpd/forms.h>
+
+CYG_HAL_TABLE_BEGIN(cyg_httpd_fvars_table, httpd_fvars_table);
+CYG_HAL_TABLE_END(cyg_httpd_fvars_table_end, httpd_fvars_table);
+
+cyg_int8 blank[] = "";
+
+cyg_int8
+cyg_httpd_from_hex(cyg_int8 c)
+{
+    if ((c >= '0') && (c <= '9'))
+        return (c - '0');
+    if ((c >= 'A') && (c <= 'F'))
+        return (c - 'A' + 10);
+    if ((c >= 'a') && (c <= 'f'))
+        return (c - 'a' + 10);
+    return -1;    
+}
+
+char*
+cyg_httpd_store_form_variable(char *query, cyg_httpd_fvars_table_entry *entry)
+{
+    char *p = query;
+    char *q = entry->buf;
+    int   len = 0;
+    
+    while (len < (entry->buflen - 1))
+        switch(*p)
+        {
+        case '%':
+            p++;
+            if (*p) 
+                *q = cyg_httpd_from_hex(*p++) * 16;
+            if (*p) 
+                *q = (*q + cyg_httpd_from_hex(*p++));
+            q++;
+            len++;
+            break;
+        case '+':
+            *q++ = ' ';
+            p++;
+            len++;
+            break;
+        case '&':
+        case ' ':
+        case '\0':        // Don't parse past the end of the packet.
+            *q++ = '\0';
+            return p;
+        default:    
+            *q++ = *p++;
+            len++;
+        }
+        while ((*p != ' ') && (*p != '&') && *p)
+            p++;
+        return p;
+} 
+
+// We'll try to parse the data from the form, and store it in the variables
+//  that have been defined by the user in the 'form_variable_table'.
+char*
+cyg_httpd_store_form_data(char *p)
+{
+    char      *p2;
+    cyg_int32 var_length;
+    cyg_httpd_fvars_table_entry *entry = cyg_httpd_fvars_table;
+    
+    // We'll clear all the variables first, to avoid stale data.
+    while (entry != cyg_httpd_fvars_table_end)
+    {
+        entry->buf[0] = '\0';
+        entry++;
+    }
+
+    if (!p)    // No form data? just return after clearing variables.
+        return NULL;
+
+    while (*p && *p != ' ')
+    {
+        if (!(p2 = strchr(p, '=')))
+            return NULL;        // Malformed post?
+        var_length = (cyg_int32)p2 - (cyg_int32)p;
+        entry = cyg_httpd_fvars_table;
+        while (entry != cyg_httpd_fvars_table_end)
+        {
+            // Compare both lenght and name.
+            // If we do not compare the lenght of the variables as well we
+            //  risk the the case where, for instance, the variable name 'foo'
+            //  hits a match with a variable name 'foobar' because the first
+            //  3 letters of the latter are the same as the former.
+            if ((strlen(entry->name) == var_length) &&
+                (strncmp((const char*)p, entry->name, var_length ) == 0))
+               break;
+            entry++;
+        }
+                
+        if (entry == cyg_httpd_fvars_table_end)
+        {
+            // No such variable. Run through the data.
+            while ((*p != '&') && (*p && *p != ' '))
+                p++;
+            if(*p == '&')
+                p++;
+            continue;
+        }
+            
+        // Found the variable, store the name.
+        p = cyg_httpd_store_form_variable(++p2, entry);
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+        diag_printf("Stored form variable: %s Value: %s\n",
+                    entry->name,
+                    entry->buf);
+#endif    
+        if (*p == '&')
+            p++;
+    }
+    return p;
+}
+
+char*
+cyg_httpd_find_form_variable(char *p)
+{
+    cyg_httpd_fvars_table_entry *entry = cyg_httpd_fvars_table;
+    
+    while (entry != cyg_httpd_fvars_table_end)
+    {
+        if (!strcmp((const char*)p, entry->name))
+            return entry->buf;
+        entry++;
+    }
+            
+    return (char*)0;
+}
+
+static inline void release_post_buffer(void)
+{
+    free(httpstate.post_data);
+    httpstate.post_data = NULL;
+    return;
+}
+    
+void
+cyg_httpd_handle_method_POST(void)
+{
+    CYG_ASSERT(httpstate.post_data == NULL, "Leftover content data");
+    CYG_ASSERT(httpstate.request_end != NULL, "Cannot see POST data");
+    if (httpstate.content_len == 0 || 
+        httpstate.content_len > CYGNUM_ATHTTPD_SERVER_MAX_POST) {
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+        return;
+    }
+    
+    // The content data is only valid during a POST.
+    httpstate.post_data = (char*)malloc(httpstate.content_len + 1);
+    CYG_ASSERT(httpstate.post_data != NULL, "Cannot malloc POST buffer");
+    if (httpstate.post_data == NULL)
+    {
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+        return;
+    }
+
+    // Grab partial/all content from data read with headers.
+    int header_len = (int)httpstate.request_end - (int)httpstate.inbuffer;
+    unsigned int post_data_available = httpstate.inbuffer_len - header_len;
+    if (httpstate.content_len < post_data_available)
+        post_data_available = httpstate.content_len;
+    
+    // Some POST data might have come along with the header frame, and the
+    //  rest is coming in on following frames. Copy the data that already
+    //  arrived into the post buffer.
+    memcpy(httpstate.post_data, httpstate.request_end, post_data_available);
+    httpstate.request_end += post_data_available;
+    unsigned int total_data_read = post_data_available;
+    
+    // Do we need additional data?
+    if (total_data_read < httpstate.content_len)
+    {
+        while (total_data_read < httpstate.content_len)
+        {
+            // Read only the data that belongs to the POST request.
+            post_data_available = read(
+                          httpstate.sockets[httpstate.client_index].descriptor,
+                          httpstate.post_data + total_data_read,
+                          httpstate.content_len - total_data_read);
+            if (post_data_available < 0)
+            {
+                release_post_buffer();
+                return;
+            }    
+            total_data_read += post_data_available;
+        }
+    }    
+    
+    // httpstate.content remains available in handler.
+    httpstate.post_data[total_data_read] = '\0';
+    
+    // The assumption here is that the data that arrived in the POST body is of
+    //  'multipart/form-data' MIME type. We need to change this if we are to
+    //  support things such as HTTP file transfer.
+    if (httpstate.mode & CYG_HTTPD_MODE_FORM_DATA)
+        cyg_httpd_store_form_data(httpstate.post_data);
+
+#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) || \
+                           defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
+    // See if we are trying to execute a CGI via one of the supported methods.
+    // If we the GET request is trying to access a file in the 
+    //  CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR directory then it is assumed that
+    //  we are trying to execute a CGI script. The extension of the file will
+    //  determine the appropriate interpreter to use.
+    if (httpstate.url[0] == '/' &&
+                    !strncmp(httpstate.url + 1, 
+                              CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR, 
+                              strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
+    {                              
+        // Here we'll look for extension to the file. We'll call the cgi
+        //  handler only if the extension is '.o'.
+        cyg_httpd_exec_cgi();
+        release_post_buffer();
+        return;
+    }
+#endif    
+    
+    handler h = cyg_httpd_find_handler();
+    if (h != 0)
+    {
+        // A handler was found. We'll call the function associated to it.
+        h(&httpstate);
+        release_post_buffer();
+        return;
+    }
+
+
+    // No handler of any kind for a post request. Must send 404.
+    cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
+    release_post_buffer();
+    return;
+}
+
+
diff --git a/packages/net/athttpd/v2_0/src/handler.c b/packages/net/athttpd/v2_0/src/handler.c
new file mode 100644 (file)
index 0000000..26e9590
--- /dev/null
@@ -0,0 +1,596 @@
+/* =================================================================
+ *
+ *      handler.c
+ *
+ *      C callbacks as well as directory listings.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: 
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <cyg/hal/hal_tables.h>
+#include <cyg/fileio/fileio.h>
+#include <dirent.h>
+#include <network.h>
+
+#include <string.h>
+#include <stdio.h>                     // sprintf().
+
+#include <cyg/athttpd/http.h>
+#include <cyg/athttpd/socket.h>
+#include <cyg/athttpd/handler.h>
+#include <cyg/athttpd/forms.h>
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
+static char folder_gif[] = {
+    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x12, 0x00,
+    0x12, 0x00, 0xd5, 0x00, 0x00, 0xfb, 0xfb, 0xfb,
+    0xef, 0xef, 0xef, 0xdb, 0xb7, 0x52, 0xcc, 0x99,
+    0x34, 0xe4, 0xe4, 0xe4, 0xc1, 0xc1, 0xc1, 0xa3,
+    0x71, 0x0b, 0xc2, 0x8f, 0x2a, 0xb7, 0xb7, 0xb7,
+    0x9e, 0x6c, 0x06, 0xba, 0x87, 0x22, 0x9c, 0x6a,
+    0x04, 0xc9, 0x96, 0x31, 0xbd, 0x8a, 0x25, 0xb3,
+    0x81, 0x1b, 0x99, 0x67, 0x01, 0xdb, 0xb7, 0x71,
+    0xb5, 0x82, 0x1d, 0xa0, 0x6e, 0x08, 0xcb, 0x98,
+    0x33, 0xff, 0xff, 0xba, 0xb0, 0x7e, 0x18, 0xc5,
+    0x92, 0x2d, 0xa7, 0x75, 0x0f, 0xc7, 0x94, 0x2f,
+    0xa6, 0xa6, 0xa6, 0xa5, 0x73, 0x0d, 0xb7, 0x84,
+    0x1f, 0xab, 0x79, 0x13, 0xc8, 0x95, 0x30, 0xc0,
+    0x8d, 0x28, 0xc6, 0xc6, 0xc6, 0xae, 0x7c, 0x16,
+    0x9a, 0x68, 0x02, 0xa8, 0x76, 0x10, 0xac, 0x7a,
+    0x14, 0xff, 0xd4, 0x6f, 0xff, 0xf8, 0x93, 0xeb,
+    0xeb, 0xeb, 0xff, 0xff, 0x9c, 0xff, 0xdb, 0x75,
+    0xff, 0xe4, 0x7f, 0xff, 0xef, 0x89, 0xb6, 0xb6,
+    0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04,
+    0x01, 0x00, 0x00, 0x2e, 0x00, 0x2c, 0x00, 0x00,
+    0x00, 0x00, 0x12, 0x00, 0x12, 0x00, 0x00, 0x06,
+    0x91, 0x40, 0x97, 0x70, 0x48, 0x2c, 0x1a, 0x8f,
+    0xc8, 0xa4, 0xd2, 0x35, 0x18, 0x4c, 0x18, 0x9d,
+    0x00, 0x40, 0x39, 0x60, 0x59, 0x29, 0x94, 0x03,
+    0x61, 0x7a, 0x1c, 0x40, 0x04, 0x60, 0x30, 0xa4,
+    0xa1, 0xd8, 0x44, 0x1c, 0x95, 0xc0, 0x70, 0x62,
+    0x6d, 0xbb, 0xdb, 0xa3, 0xcf, 0x90, 0xd1, 0x3a,
+    0xd9, 0xef, 0xf8, 0xd6, 0x05, 0x31, 0xc4, 0xb4,
+    0xfe, 0x80, 0x81, 0x7f, 0x06, 0x2b, 0x43, 0x16,
+    0x2d, 0x25, 0x89, 0x8a, 0x8b, 0x2d, 0x12, 0x85,
+    0x42, 0x07, 0x2d, 0x2a, 0x93, 0x94, 0x95, 0x2d,
+    0x09, 0x8f, 0x2e, 0x1e, 0x2d, 0x29, 0x9d, 0x9e,
+    0x9f, 0x2d, 0x0b, 0x99, 0x0d, 0x2d, 0x28, 0xa6,
+    0xa7, 0xa8, 0x2d, 0x21, 0x99, 0x0a, 0x2d, 0x24,
+    0xaf, 0xb0, 0xb1, 0x2d, 0x0f, 0x7c, 0x42, 0x01,
+    0x67, 0x15, 0x20, 0x1c, 0x22, 0x1a, 0x06, 0x12,
+    0x09, 0x0b, 0x0f, 0x19, 0x05, 0x43, 0x00, 0x04,
+    0x05, 0x2b, 0xc9, 0xca, 0xcb, 0x05, 0x04, 0x44,
+    0x00, 0x01, 0x26, 0xd2, 0xd3, 0xd4, 0x52, 0x4b,
+    0x4a, 0x41, 0x00, 0x3b
+};
+
+static char doc_gif[] = {
+    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x12, 0x00,
+    0x12, 0x00, 0xe6, 0x00, 0x00, 0xfb, 0xfb, 0xfb,
+    0xef, 0xef, 0xef, 0xf8, 0xfb, 0xff, 0xed, 0xf6,
+    0xff, 0xc1, 0xc1, 0xc1, 0xe4, 0xe4, 0xe4, 0xfd,
+    0xfd, 0xfd, 0xd8, 0xeb, 0xff, 0xc0, 0xdf, 0xff,
+    0xfe, 0xff, 0xff, 0xf3, 0xf9, 0xff, 0xc3, 0xe1,
+    0xff, 0xf4, 0xf4, 0xf5, 0xf9, 0xf9, 0xf9, 0x81,
+    0x95, 0xc3, 0x6b, 0x74, 0xa5, 0xce, 0xe7, 0xff,
+    0x5e, 0x61, 0x90, 0x55, 0xa7, 0xed, 0x93, 0xaa,
+    0xd2, 0x7a, 0x83, 0xb0, 0xc0, 0xc0, 0xff, 0xd9,
+    0xe1, 0xed, 0x84, 0x9b, 0xca, 0x8a, 0xa8, 0xd9,
+    0xe4, 0xf1, 0xff, 0x91, 0xb8, 0xea, 0x92, 0xbc,
+    0xef, 0x73, 0x7e, 0xb0, 0xf5, 0xfa, 0xff, 0xf7,
+    0xf7, 0xf7, 0x90, 0xa3, 0xcb, 0xcd, 0xe6, 0xff,
+    0xba, 0xdd, 0xff, 0xd8, 0xe5, 0xf6, 0x6d, 0x77,
+    0xa8, 0x65, 0x6a, 0x9a, 0x87, 0xa1, 0xd2, 0x7f,
+    0x8e, 0xbc, 0x8f, 0xb3, 0xe5, 0x8c, 0xae, 0xdf,
+    0xce, 0xd3, 0xff, 0xf6, 0xfa, 0xff, 0x67, 0x6d,
+    0x9e, 0xfc, 0xfd, 0xff, 0x7d, 0x89, 0xb6, 0x94,
+    0xbf, 0xf2, 0xc6, 0xc6, 0xc6, 0xfe, 0xfe, 0xfe,
+    0xdb, 0xe7, 0xf7, 0x69, 0x70, 0xa2, 0x6f, 0x7a,
+    0xac, 0x72, 0x7c, 0xae, 0x74, 0x80, 0xb2, 0x87,
+    0xa9, 0xdc, 0xd1, 0xe9, 0xff, 0xc9, 0xe4, 0xff,
+    0xb7, 0xb7, 0xb7, 0xeb, 0xeb, 0xeb, 0xb6, 0xb6,
+    0xb6, 0xe9, 0xf5, 0xff, 0x75, 0x78, 0xa3, 0xe1,
+    0xf0, 0xff, 0xdb, 0xed, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04,
+    0x01, 0x00, 0x00, 0x41, 0x00, 0x2c, 0x00, 0x00,
+    0x00, 0x00, 0x12, 0x00, 0x12, 0x00, 0x00, 0x07,
+    0xa3, 0x80, 0x41, 0x82, 0x83, 0x84, 0x85, 0x86,
+    0x87, 0x88, 0x2e, 0x36, 0x8b, 0x8c, 0x36, 0x35,
+    0x01, 0x00, 0x87, 0x1b, 0x40, 0x06, 0x00, 0x0d,
+    0x1e, 0x0c, 0x16, 0x35, 0x13, 0x90, 0x86, 0x1a,
+    0x30, 0x40, 0xa1, 0x09, 0x02, 0x31, 0x35, 0x12,
+    0x1f, 0x01, 0x86, 0x27, 0x06, 0xa2, 0x02, 0x1d,
+    0x22, 0x35, 0xb1, 0x2f, 0x86, 0x28, 0xa1, 0x02,
+    0x02, 0x03, 0x3c, 0x3c, 0x29, 0x15, 0x1c, 0x39,
+    0x86, 0x18, 0x2c, 0xb8, 0xb9, 0x3c, 0x3f, 0x3f,
+    0x07, 0x34, 0xbf, 0x85, 0x25, 0x2a, 0x0a, 0xb9,
+    0x3e, 0x3e, 0xc7, 0x37, 0x33, 0xca, 0x84, 0x17,
+    0xce, 0x3c, 0xd0, 0xc6, 0x37, 0x20, 0x23, 0xd5,
+    0x83, 0x0e, 0xba, 0xda, 0x3f, 0x37, 0x38, 0x38,
+    0x0f, 0xdf, 0x82, 0x26, 0xd9, 0xd1, 0xe4, 0xe6,
+    0x0b, 0x32, 0xe9, 0x41, 0x2d, 0x19, 0xed, 0x37,
+    0xe5, 0x0b, 0x08, 0x2b, 0xf2, 0x14, 0xf6, 0x10,
+    0xe6, 0x08, 0x42, 0x90, 0x90, 0xd7, 0xa3, 0xa0,
+    0xc1, 0x83, 0x11, 0x08, 0x18, 0x2a, 0x40, 0x60,
+    0x87, 0xc3, 0x87, 0x0e, 0x09, 0x14, 0x30, 0x04,
+    0x20, 0x80, 0x8e, 0x8b, 0x18, 0x2f, 0x76, 0x42,
+    0xc4, 0xd1, 0x50, 0x20, 0x00, 0x3b
+};
+
+static char back_gif[] = {
+    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0a, 0x00,
+    0x09, 0x00, 0xf7, 0x00, 0x00, 0xf8, 0xfa, 0xfb,
+    0x3a, 0x6b, 0x9d, 0xe5, 0xeb, 0xf2, 0x87, 0xa5,
+    0xc3, 0x9d, 0xb5, 0xce, 0xd0, 0xdc, 0xe7, 0xa9,
+    0xbe, 0xd4, 0x74, 0x97, 0xb9, 0x65, 0x8c, 0xb2,
+    0xd9, 0xe2, 0xec, 0xf1, 0xf4, 0xf8, 0xe7, 0xed,
+    0xf3, 0x55, 0x7f, 0xaa, 0xc8, 0xd6, 0xe3, 0xcc,
+    0xcc, 0xcc, 0x91, 0xac, 0xc8, 0x3f, 0x6f, 0x9f,
+    0xfd, 0xfd, 0xfe, 0x4d, 0x7a, 0xa6, 0xac, 0xc1,
+    0xd5, 0x4b, 0x78, 0xa5, 0x33, 0x66, 0x99, 0xff,
+    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x0a, 0x00, 0x09, 0x00, 0x00, 0x08,
+    0x3b, 0x00, 0x2d, 0x08, 0x1c, 0x68, 0x61, 0xc1,
+    0x83, 0x02, 0x04, 0x2d, 0x00, 0x20, 0x10, 0x80,
+    0xc2, 0x04, 0x82, 0x13, 0x28, 0x54, 0xa8, 0xe0,
+    0x50, 0x60, 0x02, 0x04, 0x13, 0x27, 0x56, 0x04,
+    0x70, 0x20, 0xa3, 0xc6, 0x87, 0x02, 0x1b, 0x30,
+    0xc8, 0x58, 0x71, 0x60, 0x04, 0x03, 0x10, 0x28,
+    0x82, 0x24, 0xa8, 0x60, 0x80, 0x84, 0x95, 0x09,
+    0x05, 0x38, 0x08, 0x08, 0x00, 0x3b
+};
+#endif
+
+// =============================================================================
+// Internal resources
+// =============================================================================
+CYG_HAL_TABLE_BEGIN(cyg_httpd_ires_table, httpd_ires_table);
+CYG_HAL_TABLE_END(cyg_httpd_ires_table_end, httpd_ires_table);
+__externC cyg_httpd_ires_table_entry cyg_httpd_ires_table[];
+__externC cyg_httpd_ires_table_entry cyg_httpd_ires_table_end[];
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
+// These threes internal resources are used for the directory listing.
+CYG_HTTPD_IRES_TABLE_ENTRY(cyg_httpd_ires_folder, \
+                           "/___folder__gif.gif", \
+                           folder_gif,            \
+                           sizeof(folder_gif));
+CYG_HTTPD_IRES_TABLE_ENTRY(cyg_httpd_ires_doc,    \
+                           "/___doc__gif.gif",    \
+                           doc_gif,               \
+                           sizeof(doc_gif));
+CYG_HTTPD_IRES_TABLE_ENTRY(cyg_httpd_ires_back,   \
+                           "/___back__gif.gif",   \
+                           back_gif,              \
+                           sizeof(back_gif));
+#endif                           
+
+cyg_httpd_ires_table_entry *
+cyg_httpd_find_ires(char *path_name)
+{
+    cyg_httpd_ires_table_entry *entry = cyg_httpd_ires_table;
+    
+    while (entry != cyg_httpd_ires_table_end)
+    {
+        if (!strcasecmp((char*)path_name, entry->f_pname))
+            return entry;
+        entry++;
+    }
+            
+    return (cyg_httpd_ires_table_entry*)NULL;
+}
+
+void 
+cyg_httpd_send_ires(cyg_httpd_ires_table_entry *entry)
+{
+    httpstate.status_code  = CYG_HTTPD_STATUS_OK;
+
+    // Here we'll look for extension to the file. Consider the case where
+    //  there might be more than one dot in the file name. We'll look for
+    //  the last dot, then we'll check the extension.
+    char *extension = rindex(entry->f_pname, '.');
+    if (extension == NULL)
+        // No extension in the file name.
+        httpstate.mime_type = 0;
+    else
+        httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
+
+    httpstate.payload_len  = entry->f_size;
+    cyg_int32 header_length = cyg_httpd_format_header();
+    
+    // As always, the header is always sent out.
+    send(httpstate.sockets[httpstate.client_index].descriptor, 
+         httpstate.outbuffer, 
+         header_length,
+         0);
+    if (httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) 
+        return;
+    cyg_httpd_write(entry->f_ptr, entry->f_size);
+}
+
+// =============================================================================
+// C callbacks
+// =============================================================================
+CYG_HAL_TABLE_BEGIN(cyg_httpd_handler_table, httpd_handler_table);
+CYG_HAL_TABLE_END(cyg_httpd_handler_table_end, httpd_handler_table);
+
+__externC cyg_httpd_handler_table_entry cyg_httpd_handler_table[];
+__externC cyg_httpd_handler_table_entry cyg_httpd_handler_table_end[];
+
+handler
+cyg_httpd_find_handler(void)
+{
+    cyg_httpd_handler_table_entry *entry = cyg_httpd_handler_table;
+    while (entry != cyg_httpd_handler_table_end)
+    {
+        if (strcmp((const char*)httpstate.url, entry->path) == 0)
+            return entry->h;
+        entry++;
+    }
+            
+    return (handler)NULL;
+}
+
+// =============================================================================
+// Directory listing
+// =============================================================================
+#ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
+void
+cyg_httpd_print_directory_entry(char *path_name, 
+                                struct stat *s, 
+                                struct dirent *de)
+{
+    char fname[CYG_HTTPD_MAXPATH];
+    char time_str[32];
+    time_t last_mod = s->st_mtime;
+
+    struct tm *mod_time = gmtime(&last_mod);
+    sprintf(time_str,
+            "%02d-%s-%04d %02d:%02d",
+            mod_time->tm_mday,
+            month_of_year[mod_time->tm_mon],
+            mod_time->tm_year + 1900,
+            mod_time->tm_hour,
+            mod_time->tm_min);
+
+    if (S_ISREG(s->st_mode))
+    {
+        strcpy(fname, path_name);
+        if (fname[strlen(fname)-1] != '/')
+            strcat(fname, "/");
+        strcat(fname, de->d_name);
+        cyg_httpd_cleanup_filename(fname);
+        sprintf(httpstate.outbuffer,
+                "<tr><td><img src='/___doc__gif.gif'></td>"
+                "<td><a href='%s'>%s</a></td>"
+                "<td>&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp</td>"
+                "<td>%s&nbsp;&nbsp;</td>"
+                "<td style='color:black'>%d</td></tr>",
+                fname,
+                de->d_name,
+                time_str,
+                (int)s->st_size);
+    }
+    else
+    {
+        strcpy(fname, "/");
+        strcat(fname, path_name);
+        if (fname[strlen(fname)-1] != '/')
+            strcat(fname, "/");
+        strcat(fname, de->d_name);
+        cyg_httpd_cleanup_filename(fname);
+        sprintf(httpstate.outbuffer,
+                "<tr><td><img src='/___folder__gif.gif'></td>"
+                "<td><a href='%s/'>%s</a></td>"
+                "<td>&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp</td>"
+                "<td>%s&nbsp;&nbsp;</td>"
+                "<td style='color:black'></td></tr>",
+                fname,
+                de->d_name,
+                time_str);
+    }
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+}
+
+void
+cyg_httpd_send_directory_listing(char *path_name)
+{
+    struct dirent next_file;
+    struct dirent last_printed;
+    struct stat s;
+    char fname[CYG_HTTPD_MAXPATH];
+
+    cyg_httpd_start_chunked("html");
+    sprintf(httpstate.outbuffer,
+            "<html><body><h3>Index of %s</h3><p></p>"
+            "<table style='font-family:courier'>",
+            path_name);
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+
+    sprintf(httpstate.outbuffer,
+            "<tr><td></td><td align='center' style='border-style:none none"
+            " solid none;border-width:thin'>Name</td>"
+            "<td style='border-style:none none solid none; border-width:thin'>"
+            "&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp</td>"
+             "<td  align='center' style='border-style:none none solid none;"
+             " border-width:thin'>Last Modified</td>"
+             "<td style='border-style:none none solid none; border-width:thin'>"
+            "Size</td></tr>");
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+
+    // Provide a pointer to the parent directory.
+    strcpy(fname, path_name);
+    if (fname[strlen(fname)-1] == '/')
+        fname[strlen(fname)-1] = '\0';
+    char *slash = rindex(fname, '/');
+    slash[1] = '\0';
+    sprintf(httpstate.outbuffer,
+            "<tr><td><img src='/___back__gif.gif'></td></td>"
+            "<td><a href='%s' style='color:red'>Parent "
+            "Directory</a></td>"
+            "<td>&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp</td>"
+            "<td>&nbsp &nbsp &nbsp &nbsp &nbsp &nbsp</td>"
+            "<td style='color:black'>-</td></tr>",
+            fname);
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+
+    strcpy(fname, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
+    if (fname[strlen(fname)-1] != '/')
+        strcat(fname, "/");
+    strcat(fname, path_name);
+    if (fname[strlen(fname)-1] != '/')
+        strcat(fname, "/");
+    cyg_httpd_cleanup_filename(fname);
+    int abs_path_len = strlen(fname);
+
+    DIR* pdir = opendir(fname);
+    struct dirent *dirent = readdir(pdir);
+
+    // First time for the directories.
+    rewinddir(pdir);
+    memset((void*)&last_printed, 0, sizeof(struct dirent));
+    dirent = readdir(pdir);
+    int new_entry = 1;
+    while (1)
+    {
+        memset((void*)&next_file, 0, sizeof(struct dirent));
+        new_entry = 0;
+        while(dirent)
+        {
+            if (strcmp(dirent->d_name, "..") &&
+                                     strcmp(dirent->d_name, "."))
+                if ((next_file.d_name[0] == '\0') ||
+                      (strcmp(next_file.d_name, dirent->d_name) > 0))
+                    if ((last_printed.d_name[0] == '\0') ||
+                      (strcmp(last_printed.d_name, dirent->d_name) < 0))
+                    {
+                        fname[abs_path_len] = '\0';
+                        strcat(fname, dirent->d_name);
+                        struct stat sp;
+                        stat(fname, &sp);
+                        if (S_ISDIR(sp.st_mode))
+                        {
+                            memcpy(&next_file, dirent, sizeof(struct dirent));
+                            memcpy(&s, &sp, sizeof(struct stat));
+                            new_entry = 1;
+                        }
+                    }
+            dirent = readdir(pdir);
+        }
+        if (new_entry == 0)
+            break;
+        cyg_httpd_print_directory_entry(path_name, &s, &next_file);
+        memcpy(&last_printed, &next_file, sizeof(struct dirent));
+        rewinddir(pdir);
+        dirent = readdir(pdir);
+    }
+
+    // A second time for the files.
+    rewinddir(pdir);
+    memset((void*)&last_printed, 0, sizeof(struct dirent));
+    dirent = readdir(pdir);
+    new_entry = 1;
+    while (1)
+    {
+        memset((void*)&next_file, 0, sizeof(struct dirent));
+        new_entry = 0;
+        while(dirent)
+        {
+            if (strcmp(dirent->d_name, "..") &&
+                                     strcmp(dirent->d_name, "."))
+                if ((next_file.d_name[0] == '\0') ||
+                      (strcmp(next_file.d_name, dirent->d_name) > 0))
+                    if ((last_printed.d_name[0] == '\0') ||
+                      (strcmp(last_printed.d_name, dirent->d_name) < 0))
+                    {
+                        fname[abs_path_len] = '\0';
+                        strcat(fname, dirent->d_name);
+                        struct stat sp;
+                        stat(fname, &sp);
+                        if (S_ISREG(sp.st_mode))
+                        {
+                            memcpy(&next_file, dirent, sizeof(struct dirent));
+                            memcpy(&s, &sp, sizeof(struct stat));
+                            new_entry = 1;
+                        }
+                    }
+            dirent = readdir(pdir);
+        }
+        if (new_entry == 0)
+            break;
+        cyg_httpd_print_directory_entry(path_name, &s, &next_file);
+        memcpy(&last_printed, &next_file, sizeof(struct dirent));
+        rewinddir(pdir);
+        dirent = readdir(pdir);
+    }
+
+    strcpy(httpstate.outbuffer, "</table><html><body>");
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+    cyg_httpd_end_chunked();
+    closedir(pdir);
+}
+#endif
diff --git a/packages/net/athttpd/v2_0/src/http.c b/packages/net/athttpd/v2_0/src/http.c
new file mode 100644 (file)
index 0000000..bb7fc28
--- /dev/null
@@ -0,0 +1,1048 @@
+/* =================================================================
+ *
+ *      http.c
+ *
+ *      Handles the client requests.
+ *
+ * ================================================================= 
+ * ####ECOSGPLCOPYRIGHTBEGIN####
+ * -------------------------------------------
+ * This file is part of eCos, the Embedded Configurable Operating
+ * System.
+ * Copyright (C) 2005, 2007 eCosCentric Ltd.
+ * 
+ * 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):    Anthony Tonizzo (atonizzo@gmail.com)
+ *  Contributors: Sergei Gavrikov (w3sg@SoftHome.net)
+ *                Lars Povlsen    (lpovlsen@vitesse.com)
+ *  Date:         2006-06-12
+ *  Purpose:      
+ *  Description:  
+ *               
+ * ####DESCRIPTIONEND####
+ * 
+ * =================================================================
+ */
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <cyg/kernel/kapi.h>           // Kernel API.
+#include <cyg/infra/diag.h>            // For diagnostic printing.
+#include <network.h>
+#include <time.h>
+
+#include <cyg/hal/hal_tables.h>
+#include <cyg/fileio/fileio.h>
+#include <stdio.h>                     // sprintf().
+#include <stdlib.h>
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER
+#include <cyg/objloader/elf.h>
+#include <cyg/objloader/objelf.h>
+#endif
+
+#include <cyg/athttpd/http.h>
+#include <cyg/athttpd/socket.h>
+#include <cyg/athttpd/handler.h>
+#include <cyg/athttpd/forms.h>
+
+cyg_int32 debug_print = 0;
+
+const char *day_of_week[7] = {"Sun", "Mon", "Tue", "Wed", 
+                                 "Thu", "Fri", "Sat"};
+const char *month_of_year[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
+                                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+const char *home_pages[] = {"index.html",   "index.htm",
+                            "default.html", "home.html"};
+CYG_HAL_TABLE_BEGIN(cyg_httpd_mime_table, httpd_mime_table);
+CYG_HAL_TABLE_END(cyg_httpd_mime_table_end, httpd_mime_table);
+
+__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table[];
+__externC cyg_httpd_mime_table_entry cyg_httpd_mime_table_end[];
+
+// Standard handlers added by default. Correspond to the most used extensions.
+// The user can add his/her own later.
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_htm_entry, "htm",
+                                       "text/html; charset=iso-8859-1");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_html_entry, "html", 
+                                       "text/html; charset=iso-8859-1");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_gif_entry, "gif", "image/gif");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_jpg_entry, "jpg", "image/jpg");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_png_entry, "png", "image/png");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_css_entry, "css", "text/css");
+CYG_HTTPD_MIME_TABLE_ENTRY(hal_js_entry, "js", "application/x-javascript");
+
+void 
+cyg_httpd_send_error(cyg_int32 err_type)
+{
+    httpstate.status_code = err_type;
+    
+    // Errors pages close the socket and are never cached.
+    httpstate.mode |= CYG_HTTPD_MODE_NO_CACHE;
+
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+    diag_printf("Sending error: %d\n", err_type);
+#endif    
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_FS
+    // Check if the user has defines his own error pages.
+    struct stat sp;
+    char file_name[CYG_HTTPD_MAXPATH];
+    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
+    if (file_name[strlen(file_name)-1] != '/')
+        strcat(file_name, "/");
+    strcat(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ERRORDIR);
+    if (file_name[strlen(file_name)-1] != '/')
+        strcat(file_name, "/");
+    sprintf(file_name + strlen(file_name), "error_%d.html", err_type);
+    cyg_httpd_cleanup_filename(file_name);
+    cyg_int32 rc = stat(file_name, &sp);
+    if (rc == 0)
+    {
+        char *extension = rindex(file_name, '.');
+        if (extension == NULL)
+            // No extension in the file name.
+            httpstate.mime_type = 0;
+        else
+            httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
+
+        httpstate.payload_len  = sp.st_size;
+        cyg_int32 header_length = cyg_httpd_format_header();
+        cyg_httpd_write(httpstate.outbuffer, header_length);
+    
+        // File found.
+        FILE *fp = fopen(file_name, "r");
+        if(fp == NULL)
+            return;
+
+        ssize_t payload_size = fread(httpstate.outbuffer, 
+                                     1, 
+                                     CYG_HTTPD_MAXOUTBUFFER, 
+                                     fp);
+        while (payload_size > 0)
+        {
+            ssize_t bytes_written = cyg_httpd_write_chunked(httpstate.outbuffer, 
+                                                            payload_size);
+            if (bytes_written != payload_size)
+                break;
+
+            payload_size = fread(httpstate.outbuffer, 
+                                 1, 
+                                 CYG_HTTPD_MAXOUTBUFFER, 
+                                 fp);
+        }
+
+        fclose(fp);
+        return;
+    }
+#endif    
+
+    // Because the size of the frame is not known upfront (every error message
+    //  is different and thus has different length) we use chunked frames to
+    //  send the message out.
+#if defined(CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS)
+    httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
+#endif
+    
+    httpstate.mode |= CYG_HTTPD_MODE_TRANSFER_CHUNKED;
+    httpstate.status_code = err_type;
+    httpstate.last_modified = -1;
+    httpstate.mime_type = "text/html";
+    cyg_int32 header_length = cyg_httpd_format_header();
+    cyg_httpd_write(httpstate.outbuffer, header_length);
+    
+    // If no file has been defined, send a simple notification. We must use
+    //  chunked frames, because we do not know upfron the length of the
+    //  packet we have to send.
+    strcpy(httpstate.outbuffer,
+           "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n");
+    switch (err_type)
+    {
+    case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
+        strcat(httpstate.outbuffer,
+               "<html><head><title>301 Moved Permanently</title></head>\r\n"
+               "<body><h1>Moved Permanently</h1>\r\n"
+               "<p>The document has moved <a href=\"");
+        strcat(httpstate.outbuffer, httpstate.url);
+        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
+        break;
+    case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>302 Found</title></head>\r\n"
+               "<body><h1>Redirect</h1>\r\n"
+               "<p>Please continue <a href=\"");
+        strcat(httpstate.outbuffer, httpstate.url);
+        strcat(httpstate.outbuffer, "\">here</a>.\r\n");
+        break;
+    case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>401 Not Authorized</title></head>\r\n");
+        strcat(httpstate.outbuffer, 
+               "<body><p>Authorization required to access this URL.</p>\r\n");
+        break;    
+    case CYG_HTTPD_STATUS_NOT_MODIFIED:
+        cyg_httpd_end_chunked();
+        return;
+    case CYG_HTTPD_STATUS_NOT_FOUND:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>404 Not Found</title></head>\r\n");
+        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                "<p>The requested URL: %s was not found on this server</p>\r\n",
+                httpstate.url);
+        break;
+    case CYG_HTTPD_STATUS_SYSTEM_ERROR:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>500 Server Error</title></head>\r\n");
+        strcat(httpstate.outbuffer, 
+               "<p>The server encountered an unexpected condition that "
+               "prevented it from fulfilling the request"
+               " by the client</p>\r\n");
+        break;
+    case CYG_HTTPD_STATUS_NOT_IMPLEMENTED:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>501 Not Implemented</title></head>\r\n");
+        strcat(httpstate.outbuffer, 
+               "<p>The method requested is not implemented</p>\r\n");
+        break;
+    default:
+        strcat(httpstate.outbuffer, 
+               "<html><head><title>400 Bad Request</title></head>\r\n");
+        strcat(httpstate.outbuffer, 
+               "<p>Bad request</p>\r\n");
+        break;
+    }
+    
+    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+            "<hr>%s at %d.%d.%d.%d Port %d\r\n</body></html>\r\n",
+            CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID,
+            httpstate.host[0],
+            httpstate.host[1],
+            httpstate.host[2],
+            httpstate.host[3],
+            CYGNUM_NET_ATHTTPD_SERVEROPT_PORT);
+    
+    cyg_httpd_write_chunked(httpstate.outbuffer, strlen(httpstate.outbuffer));
+    cyg_httpd_end_chunked();
+}
+
+// Return a time_t that is always UTC (aka GMT).
+time_t
+cyg_httpd_parse_date(char *time)
+{
+    int    i;
+    char   month[4];
+    struct tm tm_mod;
+
+    // We are going to get rid of the day of the week. This is always the first
+    //  part of the string, separated by a blank.
+    time = strchr( time, ' ');
+    if ( time == NULL)
+        return 0;
+    time++;
+
+    /// RFC1123. The date is in the format: Sun, 06 Nov 1994 08:49:37 GMT.
+    cyg_int32 rc = sscanf(time,
+                          "%2d %3s %4d %2d:%2d:%2d GMT",
+                          &tm_mod.tm_mday,
+                          month,
+                          &tm_mod.tm_year,
+                          &tm_mod.tm_hour,
+                          &tm_mod.tm_min,
+                          &tm_mod.tm_sec);
+    if (rc != 6)
+    {
+        // RFC1036. The date is in the format: Sunday, 06-Nov-94 08:49:37 GMT.
+        rc = sscanf(time,
+                    "%2d-%3s-%2d %2d:%2d:%2d GMT",
+                    &tm_mod.tm_mday,
+                    month,
+                    &tm_mod.tm_year,
+                    &tm_mod.tm_hour,
+                    &tm_mod.tm_min,
+                    &tm_mod.tm_sec);
+        if (rc != 6)
+        {
+            // asctime().
+            rc = sscanf(time,"%3s %2d %2d:%2d:%2d %4d",
+                        month,
+                        &tm_mod.tm_mday,
+                        &tm_mod.tm_hour,
+                        &tm_mod.tm_min,
+                        &tm_mod.tm_sec,
+                        &tm_mod.tm_year);
+            if (rc != 6)
+                return 0;
+        }
+    }
+
+    for (i = 0; i < sizeof(month_of_year); i++)
+        if (strcmp(month, month_of_year[i]) == 0)
+        {
+            tm_mod.tm_mon = i;
+            if (tm_mod.tm_year > 1900)
+                tm_mod.tm_year -= 1900;
+            return mktime(&tm_mod);
+        }
+
+    return 0;
+}
+
+// Finds the mime string into the mime_table associated with a specific 
+//  extension. Returns the MIME type to send in the header, or NULL if the
+//  extension is not in the table.
+char*
+cyg_httpd_find_mime_string(char *ext)
+{
+    cyg_httpd_mime_table_entry *entry = cyg_httpd_mime_table;
+
+    while (entry != cyg_httpd_mime_table_end)
+    {
+        if (!strcmp((const char*)ext, entry->extension))
+            return entry->mime_string;
+        entry++;
+    }
+            
+    return (char*)0;
+}
+
+void
+cyg_httpd_cleanup_filename(char *filename)
+{
+    char *src = strstr(filename, "//");
+    while (src != 0)
+    {
+        strcpy(src + 1, src + 2);
+        src = strstr(filename, "//");
+    }
+
+    src = strstr(filename, "/./");
+    while (src != 0)
+    {
+        strcpy(src + 1, src + 3);
+        src = strstr(filename, "/./");
+    }
+
+    src = strstr(filename, "/../");
+    while (src != 0)
+    {
+        char *comp1 = filename, *comp2 = filename;
+
+        // Search the path component before this redirection.
+        while ((comp1 = strchr(comp1, '/')) != src)
+            comp2 = ++comp1;
+
+        strcpy(comp2, src + 4);
+        src = strstr(filename, "/../");
+    }
+}
+
+cyg_int32
+cyg_httpd_initialize(void)
+{
+    httpstate.post_data = NULL;
+    httpstate.needs_auth = (cyg_httpd_auth_table_entry *)0;
+    return 0;
+}
+
+void
+cyg_httpd_append_homepage(char *root)
+{
+#ifdef CYGOPT_NET_ATHTTPD_USE_FS
+    struct stat sp;
+    cyg_int32 i;
+
+    cyg_int32 root_len = strlen(root);
+    for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
+    {
+        root[root_len] = '\0';
+        sprintf(root + root_len, "%s", home_pages[i]);
+        cyg_int32 rc = stat(root, &sp);
+        if (rc == 0)
+            return;
+    }
+    root[root_len] = 0;
+#endif    
+    
+#ifdef CYGDAT_NET_ATHTTPD_ALTERNATE_HOME    
+    if (strcmp(root, "/") == 0)
+        // The client is trying to open the main index file.
+        strcat(root, CYGDAT_NET_ATHTTPD_ALTERNATE_HOME);
+#endif    
+}
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_FS
+void
+cyg_httpd_send_file(char *name)
+{
+    cyg_int32  err;
+    FILE      *fp;
+    struct stat sp;
+    char       file_name[CYG_HTTPD_MAXPATH];
+
+    strcpy(file_name, CYGDAT_NET_ATHTTPD_SERVEROPT_ROOTDIR);
+    if (file_name[strlen(file_name)-1] != '/')
+        strcat(file_name, "/");
+    strcat(file_name, name);
+    cyg_httpd_cleanup_filename(file_name);
+        
+    // Check if the file is in the file system. This will also give us the
+    //  size of the file, to be used in the HTTP header.
+    cyg_int32 rc = stat(file_name, &sp);
+    if (rc < 0)
+    {
+        // Before giving up, we make a last ditch attempt at finding a file
+        //  within the internal resources of the server. The user can add
+        //  his/her own files to the table.
+        cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(name);
+        if (p != NULL)
+        {
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+            diag_printf("Sending Internal Resource: %s\n", name);
+#endif    
+            cyg_httpd_send_ires(p);
+        }    
+        else    
+            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
+        return;
+    }
+    
+    if (S_ISDIR(sp.st_mode))
+    {
+        char tmp_url[CYG_HTTPD_MAXURL];
+        strcpy(tmp_url, httpstate.url);
+        // Directories need a trialing slash, and if missing, we'll redirect
+        //  the client to the right URL. This is called (appropriately
+        //  enough) "Trailing-Slash Redirection". 
+        if (name[strlen(name)-1] != '/')
+        {
+            sprintf(httpstate.url,
+                    "http://%d.%d.%d.%d:%d%s/",
+                    httpstate.host[0],
+                    httpstate.host[1],
+                    httpstate.host[2],
+                    httpstate.host[3],
+                    CYGNUM_NET_ATHTTPD_SERVEROPT_PORT,
+                    tmp_url);
+            cyg_httpd_send_error(CYG_HTTPD_STATUS_MOVED_PERMANENTLY);
+            return;
+        }
+
+        // We are going to try to locate an index page in the directory we got
+        //  in the URL. 
+        cyg_httpd_append_homepage(file_name);
+        if (file_name[strlen(file_name)-1] == '/')
+        {
+#ifdef CYGOPT_NET_ATHTTPD_USE_DIRLIST
+            // No home page found, we are sending a directory listing.
+            cyg_httpd_send_directory_listing(name);
+#else
+            cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
+#endif
+            return;
+        }
+        stat(file_name, &sp);
+    }
+    
+    httpstate.last_modified = sp.st_mtime;
+
+    // Let's see if we luck out and can send a 304.
+    if ((httpstate.modified_since != -1) && 
+                   (httpstate.modified_since >= httpstate.last_modified))
+    {                   
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_MODIFIED);
+        return;
+    }    
+    else    
+        httpstate.status_code = CYG_HTTPD_STATUS_OK;
+
+    // Here we'll look for an extension to the file. Consider the case where
+    //  there might be more than one dot in the file name. We'll look for just
+    //  the last one, then we'll check the extension.
+    char *extension = rindex(file_name, '.');
+    if (extension == NULL)
+        httpstate.mime_type = 0;
+    else    
+        httpstate.mime_type = cyg_httpd_find_mime_string(++extension);
+
+    httpstate.payload_len  = sp.st_size;
+    httpstate.mode &= ~CYG_HTTPD_MODE_NO_CACHE;
+    cyg_int32 payload_size = cyg_httpd_format_header();
+    if ((httpstate.mode & CYG_HTTPD_MODE_SEND_HEADER_ONLY) != 0)
+    {                 
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+        diag_printf("Sending header only for URL: %s\n", file_name);
+#endif    
+        send(httpstate.sockets[httpstate.client_index].descriptor, 
+             httpstate.outbuffer, 
+             payload_size,
+             0);
+        return;
+    }
+
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+    diag_printf("Sending file: %s\n", file_name);
+#endif    
+    fp = fopen(file_name, "r");
+    if (fp == NULL)
+    {
+        // We should really read errno and send messages accordingly...
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+        return;
+    }
+    
+    // Fill up the rest of the buffer and send it out.
+    cyg_int32 bread = fread(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                            1, 
+                            CYG_HTTPD_MAXOUTBUFFER - payload_size,
+                            fp);
+    cyg_httpd_write(httpstate.outbuffer, payload_size + bread);
+
+    ssize_t bytes_written = 0;
+    sp.st_size -= bread;
+    while (bytes_written < sp.st_size)
+    {
+        bread = fread(httpstate.outbuffer, 1, CYG_HTTPD_MAXOUTBUFFER, fp);
+        bytes_written += cyg_httpd_write(httpstate.outbuffer, bread);
+    }    
+    
+    err = fclose(fp);
+    if (err < 0)
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_SYSTEM_ERROR);
+}
+#endif
+
+cyg_int32
+cyg_httpd_format_header(void)
+{
+    sprintf(httpstate.outbuffer, "HTTP/1.1 %d", httpstate.status_code);
+    time_t time_val = time(NULL);
+    
+    // Error messages (i.e. with status other than OK, automatically add
+    //  the no-cache header.
+    switch (httpstate.status_code)
+    {
+    case CYG_HTTPD_STATUS_MOVED_PERMANENTLY:
+        strcat(httpstate.outbuffer, " Moved Permanently\r\n");
+        strcat(httpstate.outbuffer, "Location: ");
+        strcat(httpstate.outbuffer, httpstate.url);
+        strcat(httpstate.outbuffer, "\r\n");
+        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                "Content-Length: %d\r\n",
+                httpstate.payload_len);
+        break;
+    case CYG_HTTPD_STATUS_MOVED_TEMPORARILY:
+        strcat(httpstate.outbuffer, " Found\r\n");
+        strcat(httpstate.outbuffer, "Location: ");
+        strcat(httpstate.outbuffer, httpstate.url);
+        strcat(httpstate.outbuffer, "\r\n");
+        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                "Content-Length: %d\r\n",
+                httpstate.payload_len);
+        break;
+#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
+    case CYG_HTTPD_STATUS_NOT_AUTHORIZED:
+        // A 401 error closes the connection right away.
+        httpstate.mode |= CYG_HTTPD_MODE_CLOSE_CONN;
+        strcat(httpstate.outbuffer, " Not Authorized\r\n");
+        
+        // Here we should set the proper header based on the authentication
+        //  required (httpstate.needs_authMode) but for now, with only
+        //  Basic Authentication supported, there is no need to do so.
+        if (httpstate.needs_auth->auth_mode == CYG_HTTPD_AUTH_BASIC)
+        {
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                    "WWW-Authenticate: Basic realm=\"%s\"\r\n",
+                    httpstate.needs_auth->auth_domainname);
+        }
+        else             
+        {
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                     "WWW-Authenticate: Digest realm=\"%s\", ",
+                     httpstate.needs_auth->auth_domainname);
+            strftime(cyg_httpd_md5_nonce, 
+                     33,
+                     TIME_FORMAT_RFC1123,
+                     gmtime(&time_val));
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                    "nonce=\"%s\", ", cyg_httpd_md5_nonce);
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                    "opaque=\"%s\", ", 
+                    CYG_HTTPD_MD5_AUTH_OPAQUE);
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                    "stale=false, algorithm=%s, qop=\"%s\"\r\n",
+                    CYG_HTTPD_MD5_AUTH_NAME,
+                    CYG_HTTPD_MD5_AUTH_QOP);
+        }
+        break;
+#endif
+    case CYG_HTTPD_STATUS_NOT_MODIFIED:
+        strcat(httpstate.outbuffer, " Not Modified\r\n");
+        break;
+    case CYG_HTTPD_STATUS_NOT_FOUND:
+        strcat(httpstate.outbuffer, " Not Found\r\n");
+        sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                "Content-Length: %d\r\n", 
+                httpstate.payload_len);
+        break;
+    case CYG_HTTPD_STATUS_METHOD_NOT_ALLOWED:
+        strcat(httpstate.outbuffer, " Method Not Allowed\r\n");
+        break;
+    default:
+        strcat(httpstate.outbuffer, " OK\r\n");
+        if ((httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED) == 0)
+            sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+                    "Content-Length: %d\r\n", 
+                    httpstate.payload_len);
+        break;
+    }
+
+    strcat(httpstate.outbuffer, "Date: ");
+    strftime(httpstate.outbuffer + strlen(httpstate.outbuffer), 
+             CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
+             TIME_FORMAT_RFC1123,
+             gmtime(&time_val));
+    strcat(httpstate.outbuffer, "\r\n");
+    
+    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer), 
+            "Server: %s\r\n", 
+            CYGDAT_NET_ATHTTPD_SERVEROPT_SERVERID);
+    
+    if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
+        strcat(httpstate.outbuffer, "Connection: close\r\n");
+    else
+        strcat(httpstate.outbuffer, "Connection: keep-alive\r\n");
+
+    // When we cannot find the appropriate MIME type, we'll send a default type.
+    if (httpstate.mime_type == 0)
+        httpstate.mime_type = CYGDAT_NET_ATHTTPD_DEFAULT_MIME_TYPE;
+    sprintf(httpstate.outbuffer + strlen(httpstate.outbuffer),
+            "Content-Type: %s\r\n", 
+            httpstate.mime_type);
+
+    if (httpstate.mode & CYG_HTTPD_MODE_TRANSFER_CHUNKED)
+        strcat(httpstate.outbuffer, "Transfer-Encoding: chunked\r\n");
+
+    if (httpstate.mode & CYG_HTTPD_MODE_NO_CACHE)
+        strcat(httpstate.outbuffer, "Cache-Control: no-cache\r\n");
+        
+    if (httpstate.last_modified != -1)
+    {
+        time_val = httpstate.last_modified;
+        strcat(httpstate.outbuffer, "Last-Modified: "); 
+        strftime(httpstate.outbuffer + strlen(httpstate.outbuffer), 
+                 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
+                 TIME_FORMAT_RFC1123,
+                 gmtime(&time_val));
+        strcat(httpstate.outbuffer, "\r\n");
+
+#if (CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME != 0)                 
+        time_val += CYGOPT_NET_ATHTTPD_DOCUMENT_EXPIRATION_TIME;
+        strcat(httpstate.outbuffer, "Expires: "); 
+        strftime(httpstate.outbuffer + strlen(httpstate.outbuffer), 
+                 CYG_HTTPD_MAXOUTBUFFER - strlen(httpstate.outbuffer),
+                 TIME_FORMAT_RFC1123,
+                 gmtime(&time_val));
+        strcat(httpstate.outbuffer, "\r\n");
+#endif
+    }        
+                 
+    // There must be 2 carriage returns between the header and the body, 
+    //  so if you modify this function make sure that there is another 
+    //  CRLF already terminating the buffer thus far.
+    strcat(httpstate.outbuffer, "\r\n");
+    return strlen(httpstate.outbuffer);
+}
+
+void
+cyg_httpd_handle_method_GET(void)
+{
+#if defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_OBJLOADER) ||\
+                             defined(CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL)
+    // If the URL is a CGI script, there is a different directory...
+    if (httpstate.url[0] == '/' &&
+                    !strncmp(httpstate.url + 1, 
+                              CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR, 
+                              strlen(CYGDAT_NET_ATHTTPD_SERVEROPT_CGIDIR)))
+    {                              
+        cyg_httpd_exec_cgi();
+        return;
+    }
+    // If the OBJLOADER package is not loaded, then the request for a library
+    //  will likely generate a 404.
+#endif    
+
+    // User defined handlers take precedence over other forms of response.
+    handler h = cyg_httpd_find_handler();
+    if (h != 0)
+    {
+        h(&httpstate);
+        return;
+    }
+    
+
+#ifdef CYGOPT_NET_ATHTTPD_USE_FS
+    // No handler, we'll redirect to the file system.
+    cyg_httpd_send_file(httpstate.url);
+#else
+    // If we do not have a file system, we look for the file within the 
+    //  internal resources of the server. The user can add his/her own files
+    //  to the table.
+    if (strcmp(httpstate.url, "/") == 0)
+    {
+        int i;
+        cyg_httpd_ires_table_entry *p;
+        for (i = 0; i < sizeof(home_pages)/sizeof(char*); i++)
+        {
+            httpstate.url[1] = '\0';
+            strcat(httpstate.url, home_pages[i]);
+            p = cyg_httpd_find_ires(httpstate.url);
+            if (p != NULL)
+            {
+                cyg_httpd_send_ires(p);
+                return;
+            }    
+        }        
+    }
+    else
+    {
+        cyg_httpd_ires_table_entry *p = cyg_httpd_find_ires(httpstate.url);
+        if (p != NULL)
+        {
+            cyg_httpd_send_ires(p);
+            return;
+        }    
+    }        
+    cyg_httpd_send_error(CYG_HTTPD_STATUS_NOT_FOUND);
+#endif    
+}
+
+char*
+cyg_httpd_get_URL(char* p)
+{
+    char* dest = httpstate.url;
+
+    // First get rid of multiple leading slashes.
+    while ((p[0] == '/') && (p[1] == '/'))
+       p++;
+
+    // Store the url, and check if there is a form result in it.
+    while ((*p != ' ') && (*p != '?') &&
+            ((dest - httpstate.url) <= CYG_HTTPD_MAXURL))
+    {
+        // Look for encoded characters in the URL.
+        if (*p == '%') 
+        {
+            p++;
+            cyg_int8 ch = cyg_httpd_from_hex(*p++);
+            if (ch == -1)
+            {
+                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+                return (char*)0;
+            }
+            *dest = ch << 4;
+            ch = cyg_httpd_from_hex(*p++);
+            if (ch == -1)
+            {
+                cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+                return (char*)0;
+            }
+            *dest += ch;
+            dest++;
+        }
+        else 
+            *dest++ = *p++;
+    }
+
+    // Terminate the file name...
+    *dest = '\0';
+
+    // The URL must start with a leading slash.
+    if (httpstate.url[0] != '/') 
+    {
+        cyg_httpd_send_error(CYG_HTTPD_STATUS_BAD_REQUEST);
+        return (char*)0;
+    }
+    return p;
+}
+
+char*
+cyg_httpd_parse_POST(char* p)
+{
+    httpstate.method = CYG_HTTPD_METHOD_POST;
+    char *cp = cyg_httpd_get_URL(p);
+    if (cp == 0)
+        return (char*)0;
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+    diag_printf("POST Request URL: %s\n", httpstate.url);
+#endif    
+
+    while (*cp++ != '\n');
+    return cp;
+}
+
+char*
+cyg_httpd_parse_GET(char* p)
+{
+    char *cp = cyg_httpd_get_URL(p);
+    if (cp == 0)
+        return 0;
+#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 1
+    if ( httpstate.method == CYG_HTTPD_METHOD_GET)
+        diag_printf("GET Request URL: %s\n", httpstate.url);
+    else    
+        diag_printf("HEAD Request URL: %s\n", httpstate.url);
+#endif    
+
+    if (*cp == '?')
+        // If we have a GET header with form variables we'll get the
+        //  variables out of it and store them in the variable table.
+        // Can we assume that HEAD request can have form variables?
+        // That will be a yes until I learn otherwise.
+        cp = cyg_httpd_store_form_data(++cp);
+
+    // Run to end of line.
+    while (*cp++ != '\n');
+    return cp;
+}
+
+char*
+cyg_httpd_process_header(char *p)
+{
+#ifdef CYGOPT_NET_ATHTTPD_USE_AUTH
+    // Clear the previous request's response. The client properly authenticated
+    //  will always reinitialize this variable during the header parsing
+    //  process. This variable is also commandeered to hold the hashed
+    //  username:password duo in the basic authentication.
+    cyg_httpd_md5_response[0] = '\0';
+#endif
+
+    // The deafult for HTTP 1.1 is keep-alive connections, unless specifically
+    //  closed by the far end.
+    httpstate.mode &= ~(CYG_HTTPD_MODE_CLOSE_CONN | CYG_HTTPD_MODE_FORM_DATA |\
+                                        CYG_HTTPD_MODE_SEND_HEADER_ONLY);
+    httpstate.modified_since = -1;
+    httpstate.content_len = 0;
+    while (p < httpstate.request_end)
+    {
+        if (strncasecmp("GET ", p, 4) == 0)
+        {
+            // We need separate flags for HEAD and SEND_HEADERS_ONLY since
+            //  we can send a header only even in the case of a GET request
+            //  (as a 304 response.)
+            httpstate.method = CYG_HTTPD_METHOD_GET;
+            httpstate.mode &= ~CYG_HTTPD_MODE_SEND_HEADER_ONLY;
+            p = cyg_httpd_parse_GET(p + 4);
+            if (p ==0)
+                return (char*)0;
+        }
+        else if (strncasecmp("POST ", p, 5) == 0)
+        {
+            p = cyg_httpd_parse_POST(p + 5);
+            if (p ==0)
+                return (char*)0;
+        }
+        else if (strncasecmp("HEAD ", p, 5) == 0)
+        {
+            httpstate.method = CYG_HTTPD_METHOD_HEAD;
+            httpstate.mode |= CYG_HTTPD_MODE_SEND_HEADER_ONLY;
+            p = cyg_httpd_parse_GET(p + 5);
+            if (p ==0)
+                return (char*)0;
+        }
+        else if (strncasecmp(p, "Content-Length: ", 16) == 0)
+        {
+            p = strchr(p, ':') + 2;
+            if (p)
+                // In the case of a POST request, this is the total length of
+                //  the payload, which might be spread across several frames.
+                httpstate.content_len = atoi(p);
+            while (*p++ != '\n');
+        }
+        else if (strncasecmp(p, "Content-Type: ", 14) == 0)
+        {
+            p = strchr(p, ':') + 2;
+            if (p)
+                // In the case of a POST request, this is the total length of
+                //  the payload, which might be spread across several frames.
+                if (strncasecmp(p,
+                                "application/x-www-form-urlencoded",
+                                33) == 0)
+                    httpstate.mode |= CYG_HTTPD_MODE_FORM_DATA;
+            while (*p++ != '\n');
+        }
+        else if (strncasecmp("Host:", p, 5) == 0)
+        {
+            p += 5;
+            if (*p == ' ')
+                p++;
+            sscanf(p,
+                   "%d.%d.%d.%d",
+                   &httpstate.host[0],
+                   &httpstate.host[1],
+                   &httpstate.host[2],
+                   &httpstate.host[3]);
+            while (*p++ != '\n');
+        }
+        else if (strncasecmp("If-Modified-Since:", p, 18) == 0)
+