summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-07-11 23:40:17 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2009-07-11 23:40:17 +0000
commit489c0b453b4e44764516409b62cc73e2c6149b75 (patch)
tree21820964be829a96a57b4e8a6d2bbca1a6c5f794
parentd357fd30cd6855f40dedf8050ee45067d0ee281f (diff)
downloadpx4-nuttx-489c0b453b4e44764516409b62cc73e2c6149b75.tar.gz
px4-nuttx-489c0b453b4e44764516409b62cc73e2c6149b75.tar.bz2
px4-nuttx-489c0b453b4e44764516409b62cc73e2c6149b75.zip
Add framework for thttpd
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1975 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/Makefile5
-rw-r--r--nuttx/netutils/Makefile14
-rw-r--r--nuttx/netutils/thttpd/Makefile84
-rw-r--r--nuttx/netutils/thttpd/fdwatch.h86
-rw-r--r--nuttx/netutils/thttpd/libhttpd.h339
-rw-r--r--nuttx/netutils/thttpd/mime_types.h275
-rw-r--r--nuttx/netutils/thttpd/tdate_parse.h41
-rw-r--r--nuttx/netutils/thttpd/thttpd.c947
-rw-r--r--nuttx/netutils/thttpd/timers.h144
-rw-r--r--nuttx/netutils/thttpd/version.h50
10 files changed, 1982 insertions, 3 deletions
diff --git a/nuttx/Makefile b/nuttx/Makefile
index fe917e2bc..c0b73406f 100644
--- a/nuttx/Makefile
+++ b/nuttx/Makefile
@@ -116,7 +116,7 @@ endif
# Add libraries for network support
ifeq ($(CONFIG_NET),y)
-LINKLIBS += net/libnet$(LIBEXT) netutils/libnetutils$(LIBEXT)
+LINKLIBS += net/libnet$(LIBEXT) netutils/libnetutils$(LIBEXT) netutils/libthttpd$(LIBEXT)
endif
# Add libraries for file system support
@@ -226,6 +226,9 @@ net/libnet$(LIBEXT): context
netutils/libnetutils$(LIBEXT): context
@$(MAKE) -C netutils TOPDIR="$(TOPDIR)" libnetutils$(LIBEXT)
+netutils/libthttpd$(LIBEXT): context
+ @$(MAKE) -C netutils TOPDIR="$(TOPDIR)" libthttpd$(LIBEXT)
+
fs/libfs$(LIBEXT): context
@$(MAKE) -C fs TOPDIR="$(TOPDIR)" libfs$(LIBEXT)
diff --git a/nuttx/netutils/Makefile b/nuttx/netutils/Makefile
index 15344a454..a7a9ec2ac 100644
--- a/nuttx/netutils/Makefile
+++ b/nuttx/netutils/Makefile
@@ -72,7 +72,7 @@ BIN = libnetutils$(LIBEXT)
VPATH = uiplib:dhcpc:dhcpd:resolv:smtp:telnetd:webclient:webserver:tftpc
-all: $(BIN)
+all: $(BIN) libthttpd$(LIBEXT)
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
@@ -85,6 +85,12 @@ $(BIN): $(OBJS)
$(call ARCHIVE, $@, $${obj}); \
done ; )
+thttpd/libthttpd$(LIBEXT):
+ @$(MAKE) -C thttpd libthttpd$(LIBEXT) TOPDIR="$(TOPDIR)"
+
+libthttpd$(LIBEXT): thttpd/libthttpd$(LIBEXT)
+ @cp -a thttpd/libthttpd$(LIBEXT) .
+
.depend: Makefile $(SRCS)
ifeq ($(CONFIG_NET),y)
@$(MKDEP) --dep-path . --dep-path uiplib --dep-path dhcpc --dep-path dhcpd \
@@ -95,15 +101,19 @@ endif
@touch $@
depend: .depend
+ @$(MAKE) -C thttpd depend TOPDIR="$(TOPDIR)"
clean:
- @rm -f $(BIN) *~ .*.swp
+ @rm -f $(BIN) libthttpd$(LIBEXT) *~ .*.swp
$(call CLEAN)
@( for dir in $(SUBDIRS); do \
rm -f $${dir}/*~ $${dir}/.*.swp; \
done ; )
+ @$(MAKE) -C thttpd clean TOPDIR="$(TOPDIR)"
distclean: clean
@rm -f Make.dep .depend
+ @$(MAKE) -C thttpd distclean TOPDIR="$(TOPDIR)"
-include Make.dep
+
diff --git a/nuttx/netutils/thttpd/Makefile b/nuttx/netutils/thttpd/Makefile
new file mode 100644
index 000000000..37825c2cc
--- /dev/null
+++ b/nuttx/netutils/thttpd/Makefile
@@ -0,0 +1,84 @@
+#############################################################################
+# netutils/thttpd/Makefile
+#
+# Copyright (C) 2009 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+#
+# 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
+# COPYRIGHT OWNER 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.
+#
+#############################################################################
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+
+CGIBINDIR = $(TOPDIR)/netutils/thttpd/cgi-bin
+SUBDIRS = cgi-src
+
+ASRCS =
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+
+CSRCS = thttpd.c
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+BIN = libthttpd$(LIBEXT)
+
+all: $(BIN)
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+$(BIN): $(OBJS)
+ @( for obj in $(OBJS) ; do \
+ $(call ARCHIVE, $@, $${obj}); \
+ done ; )
+
+.depend: Makefile $(SRCS)
+ @$(MKDEP) --dep-path . $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
+ @touch $@
+
+depend: .depend
+
+clean:
+ @rm -f $(BIN) *~ .*.swp
+ $(call CLEAN)
+ @( for dir in $(SUBDIRS); do \
+ rm -f $${dir}/*~ $${dir}/.*.swp; \
+ done ; )
+
+distclean: clean
+ @rm -f Make.dep .depend
+
+-include Make.dep
+
+
diff --git a/nuttx/netutils/thttpd/fdwatch.h b/nuttx/netutils/thttpd/fdwatch.h
new file mode 100644
index 000000000..76c8c02ae
--- /dev/null
+++ b/nuttx/netutils/thttpd/fdwatch.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+ * netutils/thttpd/fdwatch.h
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in THTTPD:
+ *
+ * Copyright © 1999 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_FDWATCH_H
+#define __NETUTILS_THTTPD_FDWATCH_H
+
+#define FDW_READ 0
+#define FDW_WRITE 1
+
+#ifndef INFTIM
+# define INFTIM -1
+#endif
+
+/* Figure out how many file descriptors the system allows, and
+ * initialize the fdwatch data structures. Returns -1 on failure.
+ */
+
+extern int fdwatch_get_nfiles(void);
+
+/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */
+
+extern void fdwatch_add_fd(int fd, void *client_data, int rw);
+
+/* Delete a descriptor from the watch list. */
+
+extern void fdwatch_del_fd(int fd);
+
+/* Do the watch. Return value is the number of descriptors that are ready,
+ * or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means
+ * wait indefinitely.
+ */
+
+extern int fdwatch(long timeout_msecs);
+
+/* Check if a descriptor was ready. */
+
+extern int fdwatch_check_fd(int fd);
+
+/* Get the client data for the next returned event. Returns -1 when there
+ * are no more events.
+ */
+
+extern void *fdwatch_get_next_client_data(void);
+
+/* Generate debugging statistics syslog message. */
+
+extern void fdwatch_logstats(long secs);
+
+#endif /* __NETUTILS_THTTPD_FDWATCH_H */
+
diff --git a/nuttx/netutils/thttpd/libhttpd.h b/nuttx/netutils/thttpd/libhttpd.h
new file mode 100644
index 000000000..ddd1e2d69
--- /dev/null
+++ b/nuttx/netutils/thttpd/libhttpd.h
@@ -0,0 +1,339 @@
+/****************************************************************************
+ * netutils/thttpd/libhttpd.h
+ * HTTP Protocol Library Definitions
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_LIBHTTPD_H
+#define __NETUTILS_THTTPD_LIBHTTPD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <time.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_THTTPD_PORT
+# define CONFIG_THTTPD_PORT 80
+#endif
+
+#ifndef CONFIG_THTTPD_CHARSET
+# define CONFIG_THTTPD_CHARSET "iso-8859-1"
+#endif
+
+#ifndef CONFIG_THTTPD_IOBUFFERSIZE
+# define CONFIG_THTTPD_IOBUFFERSIZE 256
+#endif
+
+#if CONFIG_THTTPD_IOBUFFERSIZE > 65535
+# error "Can't use uint16 for buffer"
+#endif
+
+/* A few convenient defines. */
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define NEW(t,n) ((t*) malloc( sizeof(t) * (n) ))
+#define RENEW(o,t,n) ((t*) realloc( (void*) o, sizeof(t) * (n) ))
+
+/* Methods. */
+
+#define METHOD_UNKNOWN 0
+#define METHOD_GET 1
+#define METHOD_HEAD 2
+#define METHOD_POST 3
+
+/* States for checked_state. */
+
+#define CHST_FIRSTWORD 0
+#define CHST_FIRSTWS 1
+#define CHST_SECONDWORD 2
+#define CHST_SECONDWS 3
+#define CHST_THIRDWORD 4
+#define CHST_THIRDWS 5
+#define CHST_LINE 6
+#define CHST_LF 7
+#define CHST_CR 8
+#define CHST_CRLF 9
+#define CHST_CRLFCR 10
+#define CHST_BOGUS 11
+
+#define GC_FAIL 0
+#define GC_OK 1
+#define GC_NO_MORE 2
+
+#define GR_NO_REQUEST 0
+#define GR_GOT_REQUEST 1
+#define GR_BAD_REQUEST 2
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+/* A multi-family sockaddr. */
+
+typedef union
+{
+ struct sockaddr sa;
+#ifdef CONFIG_NET_IPv6
+ struct sockaddr_in6 sa_in6;
+#else
+ struct sockaddr_in sa_in;
+#endif /* CONFIG_NET_IPv6 */
+} httpd_sockaddr;
+
+/* A server. */
+
+typedef struct
+{
+ char *binding_hostname;
+ char *server_hostname;
+ int cgi_count;
+ char *cwd;
+ int listen_fd;
+} httpd_server;
+
+/* A connection. */
+
+typedef struct
+{
+ int initialized;
+ httpd_server *hs;
+ httpd_sockaddr client_addr;
+ char *read_buf;
+ size_t read_size, read_idx, checked_idx;
+ int checked_state;
+ int method;
+ int status;
+ off_t bytes_to_send;
+ off_t bytes_sent;
+ char *encodedurl;
+ char *decodedurl;
+ char *protocol;
+ char *origfilename;
+ char *expnfilename;
+ char *encodings;
+ char *pathinfo;
+ char *query;
+ char *referer;
+ char *useragent;
+ char *accept;
+ char *accepte;
+ char *acceptl;
+ char *cookie;
+ char *contenttype;
+ char *reqhost;
+ char *hdrhost;
+ char *hostdir;
+ char *authorization;
+ char *remoteuser;
+ size_t maxdecodedurl, maxorigfilename, maxexpnfilename, maxencodings,
+ maxpathinfo, maxquery, maxaccept, maxaccepte, maxreqhost, maxhostdir,
+ maxremoteuser, maxresponse;
+#ifdef TILDE_MAP_2
+ char *altdir;
+ size_t maxaltdir;
+#endif /* TILDE_MAP_2 */
+ time_t if_modified_since, range_if;
+ size_t contentlength;
+ char *type; /* not malloc()ed */
+#ifdef CONFIG_THTTPD_VHOST
+ char *vhostname; /* not malloc()ed */
+#endif
+ boolean mime_flag;
+ boolean one_one; /* HTTP/1.1 or better */
+ boolean got_range;
+ boolean tildemapped; /* this connection got tilde-mapped */
+ boolean keep_alive;
+ boolean should_linger;
+ int conn_fd; /* Connection to the client */
+ int file_fd; /* Descriptor for open, outgoing file */
+ off_t range_start; /* File range start from Range= */
+ off_t range_end; /* File range end from Range= */
+ struct stat sb;
+
+ /* This is the I/O buffer that is used to buffer portions of outgoing files */
+
+ uint16 buflen; /* Index to first valid data in buffer */
+ ubyte buffer[CONFIG_THTTPD_IOBUFFERSIZE];
+} httpd_conn;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Initializes. Does the socket(), bind(), and listen(). Returns an
+ * httpd_server* which includes a socket fd that you can select() on.
+ * Return (httpd_server*) 0 on error.
+ */
+
+#ifdef CONFIG_NET_IPv6
+extern httpd_server *httpd_initialize(struct sockaddr_in6 *sa, char *cwd);
+#else
+extern httpd_server *httpd_initialize(struct sockaddr_in *sa, char *cwd);
+#endif
+
+/* Call to unlisten/close socket(s) listening for new connections. */
+
+extern void httpd_unlisten(httpd_server * hs);
+
+/* Call to shut down. */
+
+extern void httpd_terminate(httpd_server * hs);
+
+/* When a listen fd is ready to read, call this. It does the accept() and
+ * returns an httpd_conn* which includes the fd to read the request from and
+ * write the response to. Returns an indication of whether the accept()
+ * failed, succeeded, or if there were no more connections to accept.
+ *
+ * In order to minimize malloc()s, the caller passes in the httpd_conn.
+ * The caller is also responsible for setting initialized to zero before the
+ * first call using each different httpd_conn.
+ */
+
+extern int httpd_get_conn(httpd_server * hs, int listen_fd, httpd_conn * hc);
+
+/* Checks whether the data in hc->read_buf constitutes a complete request
+ * yet. The caller reads data into hc->read_buf[hc->read_idx] and advances
+ * hc->read_idx. This routine checks what has been read so far, using
+ * hc->checked_idx and hc->checked_state to keep track, and returns an
+ * indication of whether there is no complete request yet, there is a
+ * complete request, or there won't be a valid request due to a syntax error.
+ */
+
+extern int httpd_got_request(httpd_conn * hc);
+
+/* Parses the request in hc->read_buf. Fills in lots of fields in hc,
+ * like the URL and the various headers.
+ *
+ * Returns -1 on error.
+ */
+
+extern int httpd_parse_request(httpd_conn * hc);
+
+/* Starts sending data back to the client. In some cases (directories,
+ * CGI programs), finishes sending by itself - in those cases, hc->file_fd
+ * is negative. If there is more data to be sent, then hc->file_fd is a file
+ * stream for the file to send. If you don't have a current timeval
+ * handy just pass in 0.
+ *
+ * Returns -1 on error.
+ */
+
+extern int httpd_start_request(httpd_conn * hc, struct timeval *nowP);
+
+/* Actually sends any buffered response text. */
+
+extern void httpd_write_response(httpd_conn * hc);
+
+/* Call this to close down a connection and free the data. A fine point,
+ * if you fork() with a connection open you should still call this in the
+ * parent process - the connection will stay open in the child.
+ * If you don't have a current timeval handy just pass in 0.
+ */
+
+extern void httpd_close_conn(httpd_conn * hc, struct timeval *nowP);
+
+/* Call this to de-initialize a connection struct and *really* free the
+ * mallocced strings.
+ */
+
+extern void httpd_destroy_conn(httpd_conn * hc);
+
+/* Send an error message back to the client. */
+
+extern void httpd_send_err(httpd_conn * hc, int status, char *title,
+ char *extraheads, char *form, char *arg);
+
+/* Some error messages. */
+
+extern char *httpd_err400title;
+extern char *httpd_err400form;
+extern char *httpd_err408title;
+extern char *httpd_err408form;
+extern char *httpd_err503title;
+extern char *httpd_err503form;
+
+/* Generate a string representation of a method number. */
+
+extern char *httpd_method_str(int method);
+
+/* Reallocate a string. */
+
+extern void httpd_realloc_str(char **strP, size_t * maxsizeP, size_t size);
+
+/* Format a network socket to a string representation. */
+
+extern char *httpd_ntoa(httpd_sockaddr * saP);
+
+/* Set NDELAY mode on a socket. */
+
+extern void httpd_set_ndelay(int fd);
+
+/* Clear NDELAY mode on a socket. */
+
+extern void httpd_clear_ndelay(int fd);
+
+/* Generate debugging statistics syslog message. */
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+extern void httpd_logstats(long secs);
+#else
+# define httpd_logstats(secs)
+#endif
+
+/* Read to requested buffer, accounting for interruptions and EOF */
+
+extern int httpd_read(int fd, const void *buf, size_t nbytes);
+
+/* Write the buffer completely, accounting for interruptions */
+
+extern int httpd_write(int fd, const void *buf, size_t nbytes);
+
+#endif /* __NETUTILS_THTTPD_LIBHTTPD_H */
+
diff --git a/nuttx/netutils/thttpd/mime_types.h b/nuttx/netutils/thttpd/mime_types.h
new file mode 100644
index 000000000..ef2106af9
--- /dev/null
+++ b/nuttx/netutils/thttpd/mime_types.h
@@ -0,0 +1,275 @@
+/****************************************************************************
+ * netutils/thttpd/mime_types.h
+ * Provides mappings between filename extensions and MIME types and encodings.
+ *
+ * Based on mime_encodings.txt and mime_types.txt by Jef Poskanser which
+ * contained no copyright information.
+ *
+ * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_MIME_TYPES_H
+#define __NETUTILS_THTTPD_MIME_TYPES_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct mime_entry
+{
+ char *ext;
+ size_t ext_len;
+ char *val;
+ size_t val_len;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* A list of file extensions followed by the corresponding MIME encoding.
+ * Extensions not found in the table proceed to the mime_types table.
+ */
+
+static struct mime_entry enc_tab[] =
+{
+ { "Z", 0, "compress", 0 },
+ { "gz", 0, "gzip", 0 },
+ { "uu", 0, "x-uuencode", 0 },
+};
+static const int n_enc_tab = sizeof(enc_tab) / sizeof(*enc_tab);
+
+/* A list of file extensions followed by the corresponding MIME type.
+ * Extensions not found in the table are returned as text/plain.
+ */
+
+static struct mime_entry typ_tab[] =
+{
+ { "a", 0, "application/octet-stream", 0 },
+ { "aab", 0, "application/x-authorware-bin", 0 },
+ { "aam", 0, "application/x-authorware-map", 0 },
+ { "aas", 0, "application/x-authorware-seg", 0 },
+ { "ai", 0, "application/postscript", 0 },
+ { "aif", 0, "audio/x-aiff", 0 },
+ { "aifc", 0, "audio/x-aiff", 0 },
+ { "aiff", 0, "audio/x-aiff", 0 },
+ { "asc", 0, "text/plain", 0 },
+ { "asf", 0, "video/x-ms-asf", 0 },
+ { "asx", 0, "video/x-ms-asf", 0 },
+ { "au", 0, "audio/basic", 0 },
+ { "avi", 0, "video/x-msvideo", 0 },
+ { "bcpio", 0, "application/x-bcpio", 0 },
+ { "bin", 0, "application/octet-stream", 0 },
+ { "bmp", 0, "image/bmp", 0 },
+ { "cdf", 0, "application/x-netcdf", 0 },
+ { "class", 0, "application/x-java-vm", 0 },
+ { "cpio", 0, "application/x-cpio", 0 },
+ { "cpt", 0, "application/mac-compactpro", 0 },
+ { "crl", 0, "application/x-pkcs7-crl", 0 },
+ { "crt", 0, "application/x-x509-ca-cert", 0 },
+ { "csh", 0, "application/x-csh", 0 },
+ { "css", 0, "text/css", 0 },
+ { "dcr", 0, "application/x-director", 0 },
+ { "dir", 0, "application/x-director", 0 },
+ { "djv", 0, "image/vnd.djvu", 0 },
+ { "djvu", 0, "image/vnd.djvu", 0 },
+ { "dll", 0, "application/octet-stream", 0 },
+ { "dms", 0, "application/octet-stream", 0 },
+ { "doc", 0, "application/msword", 0 },
+ { "dtd", 0, "text/xml", 0 },
+ { "dump", 0, "application/octet-stream", 0 },
+ { "dvi", 0, "application/x-dvi", 0 },
+ { "dxr", 0, "application/x-director", 0 },
+ { "eps", 0, "application/postscript", 0 },
+ { "etx", 0, "text/x-setext", 0 },
+ { "exe", 0, "application/octet-stream", 0 },
+ { "ez", 0, "application/andrew-inset", 0 },
+ { "fgd", 0, "application/x-director", 0 },
+ { "fh", 0, "image/x-freehand", 0 },
+ { "fh4", 0, "image/x-freehand", 0 },
+ { "fh5", 0, "image/x-freehand", 0 },
+ { "fh7", 0, "image/x-freehand", 0 },
+ { "fhc", 0, "image/x-freehand", 0 },
+ { "gif", 0, "image/gif", 0 },
+ { "gtar", 0, "application/x-gtar", 0 },
+ { "hdf", 0, "application/x-hdf", 0 },
+ { "hqx", 0, "application/mac-binhex40", 0 },
+ { "htm", 0, "text/html; charset=%s", 0 },
+ { "html", 0, "text/html; charset=%s", 0 },
+ { "ice", 0, "x-conference/x-cooltalk", 0 },
+ { "ief", 0, "image/ief", 0 },
+ { "iges", 0, "model/iges", 0 },
+ { "igs", 0, "model/iges", 0 },
+ { "iv", 0, "application/x-inventor", 0 },
+ { "jar", 0, "application/x-java-archive", 0 },
+ { "jfif", 0, "image/jpeg", 0 },
+ { "jpe", 0, "image/jpeg", 0 },
+ { "jpeg", 0, "image/jpeg", 0 },
+ { "jpg", 0, "image/jpeg", 0 },
+ { "js", 0, "application/x-javascript", 0 },
+ { "kar", 0, "audio/midi", 0 },
+ { "latex", 0, "application/x-latex", 0 },
+ { "lha", 0, "application/octet-stream", 0 },
+ { "lzh", 0, "application/octet-stream", 0 },
+ { "m3u", 0, "audio/x-mpegurl", 0 },
+ { "man", 0, "application/x-troff-man", 0 },
+ { "mathml", 0, "application/mathml+xml", 0 },
+ { "me", 0, "application/x-troff-me", 0 },
+ { "mesh", 0, "model/mesh", 0 },
+ { "mid", 0, "audio/midi", 0 },
+ { "midi", 0, "audio/midi", 0 },
+ { "mif", 0, "application/vnd.mif", 0 },
+ { "mime", 0, "message/rfc822", 0 },
+ { "mml", 0, "application/mathml+xml", 0 },
+ { "mov", 0, "video/quicktime", 0 },
+ { "movie", 0, "video/x-sgi-movie", 0 },
+ { "mp2", 0, "audio/mpeg", 0 },
+ { "mp3", 0, "audio/mpeg", 0 },
+ { "mp4", 0, "video/mp4", 0 },
+ { "mpe", 0, "video/mpeg", 0 },
+ { "mpeg", 0, "video/mpeg", 0 },
+ { "mpg", 0, "video/mpeg", 0 },
+ { "mpga", 0, "audio/mpeg", 0 },
+ { "ms", 0, "application/x-troff-ms", 0 },
+ { "msh", 0, "model/mesh", 0 },
+ { "mv", 0, "video/x-sgi-movie", 0 },
+ { "mxu", 0, "video/vnd.mpegurl", 0 },
+ { "nc", 0, "application/x-netcdf", 0 },
+ { "o", 0, "application/octet-stream", 0 },
+ { "oda", 0, "application/oda", 0 },
+ { "ogg", 0, "application/x-ogg", 0 },
+ { "pac", 0, "application/x-ns-proxy-autoconfig", 0 },
+ { "pbm", 0, "image/x-portable-bitmap", 0 },
+ { "pdb", 0, "chemical/x-pdb", 0 },
+ { "pdf", 0, "application/pdf", 0 },
+ { "pgm", 0, "image/x-portable-graymap", 0 },
+ { "pgn", 0, "application/x-chess-pgn", 0 },
+ { "png", 0, "image/png", 0 },
+ { "pnm", 0, "image/x-portable-anymap", 0 },
+ { "ppm", 0, "image/x-portable-pixmap", 0 },
+ { "ppt", 0, "application/vnd.ms-powerpoint", 0 },
+ { "ps", 0, "application/postscript", 0 },
+ { "qt", 0, "video/quicktime", 0 },
+ { "ra", 0, "audio/x-realaudio", 0 },
+ { "ram", 0, "audio/x-pn-realaudio", 0 },
+ { "ras", 0, "image/x-cmu-raster", 0 },
+ { "rdf", 0, "application/rdf+xml", 0 },
+ { "rgb", 0, "image/x-rgb", 0 },
+ { "rm", 0, "audio/x-pn-realaudio", 0 },
+ { "roff", 0, "application/x-troff", 0 },
+ { "rpm", 0, "audio/x-pn-realaudio-plugin", 0 },
+ { "rss", 0, "application/rss+xml", 0 },
+ { "rtf", 0, "text/rtf", 0 },
+ { "rtx", 0, "text/richtext", 0 },
+ { "sgm", 0, "text/sgml", 0 },
+ { "sgml", 0, "text/sgml", 0 },
+ { "sh", 0, "application/x-sh", 0 },
+ { "shar", 0, "application/x-shar", 0 },
+ { "silo", 0, "model/mesh", 0 },
+ { "sit", 0, "application/x-stuffit", 0 },
+ { "skd", 0, "application/x-koan", 0 },
+ { "skm", 0, "application/x-koan", 0 },
+ { "skp", 0, "application/x-koan", 0 },
+ { "skt", 0, "application/x-koan", 0 },
+ { "smi", 0, "application/smil", 0 },
+ { "smil", 0, "application/smil", 0 },
+ { "snd", 0, "audio/basic", 0 },
+ { "so", 0, "application/octet-stream", 0 },
+ { "spl", 0, "application/x-futuresplash", 0 },
+ { "src", 0, "application/x-wais-source", 0 },
+ { "stc", 0, "application/vnd.sun.xml.calc.template", 0 },
+ { "std", 0, "application/vnd.sun.xml.draw.template", 0 },
+ { "sti", 0, "application/vnd.sun.xml.impress.template", 0 },
+ { "stw", 0, "application/vnd.sun.xml.writer.template", 0 },
+ { "sv4cpio", 0, "application/x-sv4cpio", 0 },
+ { "sv4crc", 0, "application/x-sv4crc", 0 },
+ { "svg", 0, "image/svg+xml", 0 },
+ { "svgz", 0, "image/svg+xml", 0 },
+ { "swf", 0, "application/x-shockwave-flash", 0 },
+ { "sxc", 0, "application/vnd.sun.xml.calc", 0 },
+ { "sxd", 0, "application/vnd.sun.xml.draw", 0 },
+ { "sxg", 0, "application/vnd.sun.xml.writer.global", 0 },
+ { "sxi", 0, "application/vnd.sun.xml.impress", 0 },
+ { "sxm", 0, "application/vnd.sun.xml.math", 0 },
+ { "sxw", 0, "application/vnd.sun.xml.writer", 0 },
+ { "t", 0, "application/x-troff", 0 },
+ { "tar", 0, "application/x-tar", 0 },
+ { "tcl", 0, "application/x-tcl", 0 },
+ { "tex", 0, "application/x-tex", 0 },
+ { "texi", 0, "application/x-texinfo", 0 },
+ { "texinfo", 0, "application/x-texinfo", 0 },
+ { "tif", 0, "image/tiff", 0 },
+ { "tiff", 0, "image/tiff", 0 },
+ { "tr", 0, "application/x-troff", 0 },
+ { "tsp", 0, "application/dsptype", 0 },
+ { "tsv", 0, "text/tab-separated-values", 0 },
+ { "txt", 0, "text/plain; charset=%s", 0 },
+ { "ustar", 0, "application/x-ustar", 0 },
+ { "vcd", 0, "application/x-cdlink", 0 },
+ { "vrml", 0, "model/vrml", 0 },
+ { "vx", 0, "video/x-rad-screenplay", 0 },
+ { "wav", 0, "audio/x-wav", 0 },
+ { "wax", 0, "audio/x-ms-wax", 0 },
+ { "wbmp", 0, "image/vnd.wap.wbmp", 0 },
+ { "wbxml", 0, "application/vnd.wap.wbxml", 0 },
+ { "wm", 0, "video/x-ms-wm", 0 },
+ { "wma", 0, "audio/x-ms-wma", 0 },
+ { "wmd", 0, "application/x-ms-wmd", 0 },
+ { "wml", 0, "text/vnd.wap.wml", 0 },
+ { "wmlc", 0, "application/vnd.wap.wmlc", 0 },
+ { "wmls", 0, "text/vnd.wap.wmlscript", 0 },
+ { "wmlsc", 0, "application/vnd.wap.wmlscriptc", 0 },
+ { "wmv", 0, "video/x-ms-wmv", 0 },
+ { "wmx", 0, "video/x-ms-wmx", 0 },
+ { "wmz", 0, "application/x-ms-wmz", 0 },
+ { "wrl", 0, "model/vrml", 0 },
+ { "wsrc", 0, "application/x-wais-source", 0 },
+ { "wvx", 0, "video/x-ms-wvx", 0 },
+ { "xbm", 0, "image/x-xbitmap", 0 },
+ { "xht", 0, "application/xhtml+xml", 0 },
+ { "xhtml", 0, "application/xhtml+xml", 0 },
+ { "xls", 0, "application/vnd.ms-excel", 0 },
+ { "xml", 0, "text/xml", 0 },
+ { "xpm", 0, "image/x-xpixmap", 0 },
+ { "xsl", 0, "text/xml", 0 },
+ { "xwd", 0, "image/x-xwindowdump", 0 },
+ { "xyz", 0, "chemical/x-xyz", 0 },
+ { "zip", 0, "application/zip", 0 },
+};
+static const int n_typ_tab = sizeof(typ_tab) / sizeof(*typ_tab);
+
+#endif /* __NETUTILS_THTTPD_MIME_TYPES_H */
+
diff --git a/nuttx/netutils/thttpd/tdate_parse.h b/nuttx/netutils/thttpd/tdate_parse.h
new file mode 100644
index 000000000..301d5467a
--- /dev/null
+++ b/nuttx/netutils/thttpd/tdate_parse.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ * netutils/thttpd/fdwatch.h
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in THTTPD:
+ *
+ * Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_TDATE_PARSE_H
+#define __NETUTILS_TDATE_PARSE_H
+
+extern time_t tdate_parse(char *str);
+
+#endif /* __NETUTILS_TDATE_PARSE_H */
diff --git a/nuttx/netutils/thttpd/thttpd.c b/nuttx/netutils/thttpd/thttpd.c
new file mode 100644
index 000000000..2d45b611a
--- /dev/null
+++ b/nuttx/netutils/thttpd/thttpd.c
@@ -0,0 +1,947 @@
+/****************************************************************************
+ * netutils/thttpd/thttpd.c
+ * Tiny HTTP Server
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in the original THTTPD package:
+ *
+ * Copyright © 1995,1998,1999,2000,2001 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/compiler.h>
+
+#include "version.h"
+#include "fdwatch.h"
+#include "libhttpd.h"
+#include "timers.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_THTTPD_IPADDR
+# warning "CONFIG_THTTPD_IPADDR not defined"
+# define CONFIG_THTTPD_IPADDR (10<<24|0<<16|0<<8|2)
+#endif
+
+#ifndef CONFIG_THTTPD_LINGER_MSEC
+# define CONFIG_THTTPD_LINGER_MSEC 5000
+#endif
+
+#ifndef CONFIG_THTTPD_OCCASIONAL_MSEC
+# define CONFIG_THTTPD_OCCASIONAL_MSEC 2000
+#endif
+
+#ifndef CONFIG_THTTPD_IDLE_READ_LIMIT_SEC
+# define CONFIG_THTTPD_IDLE_READ_LIMIT_SEC 5
+#endif
+
+#ifndef CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC
+# define CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC 5
+#endif
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 64
+#endif
+
+/* The connection states */
+
+#define CNST_FREE 0
+#define CNST_READING 1
+#define CNST_SENDING 2
+#define CNST_PAUSING 3
+#define CNST_LINGERING 4
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct connect_s
+{
+ int conn_state;
+ int next_free_connect;
+ httpd_conn *hc;
+ time_t active_at;
+ Timer *wakeup_timer;
+ Timer *linger_timer;
+ off_t end_offset; /* The final offset+1 of the file to send */
+ off_t offset; /* The current offset into the file to send */
+ boolean eof; /* Set TRUE when length==0 read from file */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static httpd_server *hs = NULL;
+static struct connect_s *connects;
+static int num_connects;
+static int max_connects;
+static int first_free_connect;
+static int httpd_conn_count;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+int terminate = 0;
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+time_t start_time;
+time_t stats_time;
+long stats_connections;
+off_t stats_bytes;
+int stats_simultaneous;
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void shut_down(void);
+static int handle_newconnect(struct timeval *tv, int listen_fd);
+static void handle_read(struct connect_s *conn, struct timeval *tv);
+static void handle_send(struct connect_s *conn, struct timeval *tv);
+static void handle_linger(struct connect_s *conn, struct timeval *tv);
+static void finish_connection(struct connect_s *conn, struct timeval *tv);
+static void clear_connection(struct connect_s *conn, struct timeval *tv);
+static void really_clear_connection(struct connect_s *conn, struct timeval *tv);
+static void idle(ClientData client_data, struct timeval *nowP);
+static void linger_clear_connection(ClientData client_data, struct timeval *nowP);
+static void occasional(ClientData client_data, struct timeval *nowP);
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+static void logstats(struct timeval *nowP);
+static void thttpd_logstats(long secs);
+#else
+# define logstats(nowP)
+# define thttpd_logstats(secs)
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void shut_down(void)
+{
+ int cnum;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ logstats(&tv);
+ for (cnum = 0; cnum < max_connects; ++cnum)
+ {
+ if (connects[cnum].conn_state != CNST_FREE)
+ {
+ httpd_close_conn(connects[cnum].hc, &tv);
+ }
+
+ if (connects[cnum].hc != (httpd_conn *) 0)
+ {
+ httpd_destroy_conn(connects[cnum].hc);
+ free((void *)connects[cnum].hc);
+ --httpd_conn_count;
+ connects[cnum].hc = (httpd_conn *) 0;
+ }
+ }
+
+ if (hs != (httpd_server *) 0)
+ {
+ httpd_server *ths = hs;
+ hs = (httpd_server *) 0;
+ if (ths->listen_fd != -1)
+ {
+ fdwatch_del_fd(ths->listen_fd);
+ }
+ httpd_terminate(ths);
+ }
+
+ tmr_destroy();
+ free((void *)connects);
+}
+
+static int handle_newconnect(struct timeval *tv, int listen_fd)
+{
+ struct connect_s *conn;
+ ClientData client_data;
+
+ /* This loops until the accept() fails, trying to start new connections as
+ * fast as possible so we don't overrun the listen queue.
+ */
+
+ for (;;)
+ {
+ /* Is there room in the connection table? */
+ if (num_connects >= max_connects)
+ {
+ /* Out of connection slots. Run the timers, then the existing
+ * connections, and maybe we'll free up a slot by the time we get
+ * back here. */
+ ndbg("too many connections!\n");
+ tmr_run(tv);
+ return 0;
+ }
+
+ /* Get the first free connection entry off the free list */
+
+ if (first_free_connect == -1 ||
+ connects[first_free_connect].conn_state != CNST_FREE)
+ {
+ ndbg("the connects free list is messed up\n");
+ exit(1);
+ }
+
+ conn = &connects[first_free_connect];
+
+ /* Make the httpd_conn if necessary */
+
+ if (conn->hc == (httpd_conn *) 0)
+ {
+ conn->hc = NEW(httpd_conn, 1);
+ if (conn->hc == (httpd_conn *) 0)
+ {
+ ndbg("out of memory allocating an httpd_conn\n");
+ exit(1);
+ }
+ conn->hc->initialized = 0;
+ ++httpd_conn_count;
+ }
+
+ /* Get the connection */
+
+ switch (httpd_get_conn(hs, listen_fd, conn->hc))
+ {
+ /* Some error happened. Run the timers, then the existing
+ * connections. Maybe the error will clear.
+ */
+
+ case GC_FAIL:
+ tmr_run(tv);
+ return 0;
+
+ /* No more connections to accept for now */
+
+ case GC_NO_MORE:
+ return 1;
+ }
+
+ conn->conn_state = CNST_READING;
+
+ /* Pop it off the free list */
+
+ first_free_connect = conn->next_free_connect;
+ conn->next_free_connect = -1;
+ ++num_connects;
+ client_data.p = conn;
+ conn->active_at = tv->tv_sec;
+ conn->wakeup_timer = (Timer *) 0;
+ conn->linger_timer = (Timer *) 0;
+ conn->offset = 0;
+
+ /* Set the connection file descriptor to no-delay mode */
+
+ httpd_set_ndelay(conn->hc->conn_fd);
+
+ fdwatch_add_fd(conn->hc->conn_fd, conn, FDW_READ);
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+ ++stats_connections;
+ if (num_connects > stats_simultaneous)
+ stats_simultaneous = num_connects;
+#endif
+ }
+}
+
+static void handle_read(struct connect_s *conn, struct timeval *tv)
+{
+ ClientData client_data;
+ httpd_conn *hc = conn->hc;
+ off_t actual;
+ int sz;
+
+ /* Is there room in our buffer to read more bytes? */
+
+ if (hc->read_idx >= hc->read_size)
+ {
+ if (hc->read_size > 5000)
+ {
+ goto errout_with_400;
+ }
+ httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + 1000);
+ }
+
+ /* Read some more bytes */
+
+ sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx);
+ if (sz == 0)
+ {
+ goto errout_with_400;
+ }
+
+ if (sz < 0)
+ {
+ /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glanc
+ * you would think that connections returned by fdwatch as readable
+ * should never give an EWOULDBLOCK; however, this apparently can
+ * happen if a packet gets garbled.
+ */
+
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+ {
+ return;
+ }
+ goto errout_with_400;
+ }
+
+ hc->read_idx += sz;
+ conn->active_at = tv->tv_sec;
+
+ /* Do we have a complete request yet? */
+
+ switch (httpd_got_request(hc))
+ {
+ case GR_NO_REQUEST:
+ return;
+ case GR_BAD_REQUEST:
+ goto errout_with_400;
+ }
+
+ /* Yes. Try parsing and resolving it */
+
+ if (httpd_parse_request(hc) < 0)
+ {
+ goto errout_with_connection;
+ }
+
+ /* Start the connection going */
+
+ if (httpd_start_request(hc, tv) < 0)
+ {
+ /* Something went wrong. Close down the connection */
+
+ goto errout_with_connection;
+ }
+
+ /* Set up the file offsets to read */
+
+ conn->eof = FALSE;
+ if (hc->got_range)
+ {
+ conn->offset = hc->range_start;
+ conn->end_offset = hc->range_end + 1;
+ }
+ else
+ {
+ conn->offset = 0;
+ if (hc->bytes_to_send < 0)
+ {
+ conn->end_offset = 0;
+ }
+ else
+ {
+ conn->end_offset = hc->bytes_to_send;
+ }
+ }
+
+ /* Check if it's already handled */
+
+ if (hc->file_fd < 0)
+ {
+ /* No file descriptor means someone else is handling it */
+
+ conn->offset = hc->bytes_sent;
+ goto errout_with_connection;
+ }
+
+ if (conn->offset >= conn->end_offset)
+ {
+ /* There's nothing to send */
+
+ goto errout_with_connection;
+ }
+
+ /* Seek to the offset of the next byte to send */
+
+ actual = lseek(hc->file_fd, conn->offset, SEEK_SET);
+ if (actual != conn->offset)
+ {
+ ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno);
+ goto errout_with_400;
+ }
+
+ /* We have a valid connection and a file to send to it */
+
+ conn->conn_state = CNST_SENDING;
+ client_data.p = conn;
+
+ fdwatch_del_fd(hc->conn_fd);
+ fdwatch_add_fd(hc->conn_fd, conn, FDW_WRITE);
+ return;
+
+errout_with_400:
+ httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, "");
+
+errout_with_connection:
+ finish_connection(conn, tv);
+ return;
+}
+
+static inline int read_buffer(struct connect_s *conn)
+{
+ httpd_conn *hc = conn->hc;
+ ssize_t nread = 0;
+
+ if (hc->buflen < CONFIG_THTTPD_IOBUFFERSIZE && !conn->eof)
+ {
+ nread = read(hc->file_fd, &hc->buffer[hc->buflen],
+ CONFIG_THTTPD_IOBUFFERSIZE - hc->buflen);
+ if (nread == 0)
+ {
+ /* Reading zero bytes means we are at the end of file */
+
+ conn->end_offset = conn->offset;
+ conn->eof = TRUE;
+ }
+ else if (nread > 0)
+ {
+ hc->buflen += nread;
+ }
+ }
+ return nread;
+}
+
+static void handle_send(struct connect_s *conn, struct timeval *tv)
+{
+ httpd_conn *hc = conn->hc;
+ int nwritten;
+ int nread;
+
+ /* Fill the rest of the response buffer with file data */
+
+ nread = read_buffer(conn);
+ if (nread < 0)
+ {
+ ndbg("File read error: %d\n", errno);
+ goto errout_clear_connection;
+ }
+
+ /* Send the buffer */
+
+ if (hc->buflen > 0)
+ {
+ nwritten = httpd_write(hc->conn_fd, hc->buffer, hc->buflen);
+ if (nwritten < 0)
+ {
+ ndbg("Error sending %s: %d\n", hc->encodedurl, errno);
+ goto errout_clear_connection;
+ }
+
+ /* We wrote one full buffer of data (httpd_write does not
+ * return until the full buffer is written (or an error occurs).
+ */
+
+ conn->active_at = tv->tv_sec;
+ hc->buflen = 0;
+
+ /* And update how much of the file we wrote */
+
+ conn->offset += nread;
+ conn->hc->bytes_sent += nread;
+ }
+
+ /* Are we done? */
+
+ if (conn->offset >= conn->end_offset)
+ {
+ /* This connection is finished! */
+
+ finish_connection(conn, tv);
+ return;
+ }
+
+errout_clear_connection:
+ clear_connection(conn, tv);
+ return;
+}
+
+static void handle_linger(struct connect_s *conn, struct timeval *tv)
+{
+ char buf[4096];
+ int ret;
+
+ /* In lingering-close mode we just read and ignore bytes. An error or EOF
+ * ends things, otherwise we go until a timeout
+ */
+
+ ret = read(conn->hc->conn_fd, buf, sizeof(buf));
+ if (ret < 0 && (errno == EINTR || errno == EAGAIN))
+ {
+ return;
+ }
+
+ if (ret <= 0)
+ {
+ really_clear_connection(conn, tv);
+ }
+}
+
+static void finish_connection(struct connect_s *conn, struct timeval *tv)
+{
+ /* If we haven't actually sent the buffered response yet, do so now */
+
+ httpd_write_response(conn->hc);
+
+ /* And clear */
+
+ clear_connection(conn, tv);
+}
+
+static void clear_connection(struct connect_s *conn, struct timeval *tv)
+{
+ ClientData client_data;
+
+ if (conn->wakeup_timer != (Timer *) 0)
+ {
+ tmr_cancel(conn->wakeup_timer);
+ conn->wakeup_timer = 0;
+ }
+
+ /* This is our version of Apache's lingering_close() routine, which is
+ * their version of the often-broken SO_LINGER socket option. For why
+ * this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html
+ * What we do is delay the actual closing for a few seconds, while reading
+ * any bytes that come over the connection. However, we don't want to do
+ * this unless it's necessary, because it ties up a connection slot and
+ * file descriptor which means our maximum connection-handling rateis
+ * lower. So, elsewhere we set a flag when we detect the few
+ * circumstances that make a lingering close necessary. If the flag isn't
+ * set we do the real close now.
+ */
+
+ if (conn->conn_state == CNST_LINGERING)
+ {
+ /* If we were already lingering, shut down for real */
+
+ tmr_cancel(conn->linger_timer);
+ conn->linger_timer = (Timer *) 0;
+ conn->hc->should_linger = FALSE;
+ }
+
+ if (conn->hc->should_linger)
+ {
+ if (conn->conn_state != CNST_PAUSING)
+ {
+ fdwatch_del_fd(conn->hc->conn_fd);
+ }
+
+ conn->conn_state = CNST_LINGERING;
+ close(conn->hc->conn_fd);
+ fdwatch_add_fd(conn->hc->conn_fd, conn, FDW_READ);
+ client_data.p = conn;
+
+ if (conn->linger_timer != (Timer *) 0)
+ {
+ ndbg("replacing non-null linger_timer!\n");
+ }
+
+ conn->linger_timer =
+ tmr_create(tv, linger_clear_connection, client_data, CONFIG_THTTPD_LINGER_MSEC, 0);
+ if (conn->linger_timer == (Timer *) 0)
+ {
+ ndbg("tmr_create(linger_clear_connection) failed\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ really_clear_connection(conn, tv);
+ }
+}
+
+static void really_clear_connection(struct connect_s *conn, struct timeval *tv)
+{
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+ stats_bytes += conn->hc->bytes_sent;
+#endif
+ if (conn->conn_state != CNST_PAUSING)
+ {
+ fdwatch_del_fd(conn->hc->conn_fd);
+ }
+
+ httpd_close_conn(conn->hc, tv);
+ if (conn->linger_timer != (Timer *) 0)
+ {
+ tmr_cancel(conn->linger_timer);
+ conn->linger_timer = 0;
+ }
+
+ conn->conn_state = CNST_FREE;
+ conn->next_free_connect = first_free_connect;
+ first_free_connect = conn - connects; /* division by sizeof is implied */
+ num_connects--;
+}
+
+static void idle(ClientData client_data, struct timeval *nowP)
+{
+ int cnum;
+ struct connect_s *conn;
+
+ for (cnum = 0; cnum < max_connects; ++cnum)
+ {
+ conn = &connects[cnum];
+ switch (conn->conn_state)
+ {
+ case CNST_READING:
+ if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC)
+ {
+ ndbg("%s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr));
+ httpd_send_err(conn->hc, 408, httpd_err408title, "",
+ httpd_err408form, "");
+ finish_connection(conn, nowP);
+ }
+ break;
+
+ case CNST_SENDING:
+ case CNST_PAUSING:
+ if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC)
+ {
+ ndbg("%s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr));
+ clear_connection(conn, nowP);
+ }
+ break;
+ }
+ }
+}
+
+static void linger_clear_connection(ClientData client_data, struct timeval *nowP)
+{
+ struct connect_s *conn;
+
+ conn = (struct connect_s *) client_data.p;
+ conn->linger_timer = (Timer *) 0;
+ really_clear_connection(conn, nowP);
+}
+
+static void occasional(ClientData client_data, struct timeval *nowP)
+{
+ tmr_cleanup();
+}
+
+/* Generate debugging statistics ndbg messages for all packages */
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+static void logstats(struct timeval *nowP)
+{
+ struct timeval tv;
+ time_t now;
+ long up_secs;
+ long stats_secs;
+
+ if (nowP == (struct timeval *)0)
+ {
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ nowP = &tv;
+ }
+
+ now = nowP->tv_sec;
+ up_secs = now - start_time;
+ stats_secs = now - stats_time;
+ if (stats_secs == 0)
+ {
+ stats_secs = 1; /* fudge */
+ }
+
+ stats_time = now;
+ ndbg("up %ld seconds, stats for %ld seconds\n", up_secs, stats_secs);
+
+ thttpd_logstats(stats_secs);
+ httpd_logstats(stats_secs);
+ fdwatch_logstats(stats_secs);
+ tmr_logstats(stats_secs);
+}
+#endif
+
+/* Generate debugging statistics */
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+static void thttpd_logstats(long secs)
+{
+ if (secs > 0)
+ {
+ ndbg("thttpd - %ld connections (%g/sec), %d max simultaneous, %lld bytes (%g/sec), %d httpd_conns allocated\n",
+ stats_connections, (float)stats_connections / secs,
+ stats_simultaneous, (sint64) stats_bytes,
+ (float)stats_bytes / secs, httpd_conn_count);
+ }
+
+ stats_connections = 0;
+ stats_bytes = 0;
+ stats_simultaneous = 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int thttpd_main(int argc, char **argv)
+{
+ char cwd[MAXPATHLEN + 1];
+ int num_ready;
+ int cnum;
+ struct connect_s *conn;
+ httpd_conn *hc;
+#ifdef CONFIG_NET_IPv6
+ struct sockaddr_in6 sa;
+#else
+ struct sockaddr_in sa;
+#endif
+ struct timeval tv;
+
+ /* Setup host address */
+
+#ifdef CONFIG_NET_IPv6
+# error "IPv6 support not yet implemented"
+#else
+ sa.sin_family = AF_INET;
+ sa.sin_port = HTONS(CONFIG_THTTPD_PORT);
+ sa.sin_addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR);
+#endif
+
+ /* Switch directories if requested */
+
+#ifdef CONFIG_THTTPD_DIR
+ if (chdir(CONFIG_THTTPD_DIR) < 0)
+ {
+ ndbg("chdir: %d\n", errno);
+ exit(1);
+ }
+#endif
+
+ /* Get current directory */
+
+ (void)getcwd(cwd, sizeof(cwd) - 1);
+ if (cwd[strlen(cwd) - 1] != '/')
+ {
+ (void)strcat(cwd, "/");
+ }
+
+ /* Initialize the fdwatch package */
+
+ max_connects = fdwatch_get_nfiles();
+ if (max_connects < 0)
+ {
+ ndbg("fdwatch initialization failure\n");
+ exit(1);
+ }
+
+ /* Switch directories again if requested */
+
+#ifdef CONFIG_THTTPD_DATADIR
+ if (chdir(CONFIG_THTTPD_DATADIR) < 0)
+ {
+ ndbg("chdir to %s: %d\n", CONFIG_THTTPD_DATADIR, errno);
+ exit(1);
+ }
+#endif
+
+ /* Initialize the timer package */
+
+ tmr_init();
+
+ /* Initialize the HTTP layer */
+
+ hs = httpd_initialize(&sa, cwd);
+ if (!hs)
+ {
+ exit(1);
+ }
+
+ /* Set up the occasional timer */
+
+ if (tmr_create
+ ((struct timeval *)0, occasional, JunkClientData, CONFIG_THTTPD_OCCASIONAL_MSEC * 1000L,
+ 1) == (Timer *) 0)
+ {
+ ndbg("tmr_create(occasional) failed\n");
+ exit(1);
+ }
+
+ /* Set up the idle timer */
+
+ if (tmr_create((struct timeval *)0, idle, JunkClientData, 5 * 1000L, 1) ==
+ (Timer *) 0)
+ {
+ ndbg("tmr_create(idle) failed\n");
+ exit(1);
+
+ }
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+ {
+ struct timeval ts;
+ gettimeofday(&ts, NULL);
+ start_time = ts.tv_sec;
+ stats_time = ts.tv_sec;
+ stats_connections = 0;
+ stats_bytes = 0;
+ stats_simultaneous = 0;
+ }
+#endif
+
+ /* Initialize our connections table */
+
+ connects = NEW(struct connect_s, max_connects);
+ if (connects == (struct connect_s *) 0)
+ {
+ ndbg("out of memory allocating a struct connect_s\n");
+ exit(1);
+ }
+
+ for (cnum = 0; cnum < max_connects; ++cnum)
+ {
+ connects[cnum].conn_state = CNST_FREE;
+ connects[cnum].next_free_connect = cnum + 1;
+ connects[cnum].hc = (httpd_conn *) 0;
+ }
+
+ connects[max_connects - 1].next_free_connect = -1; /* end of link list */
+ first_free_connect = 0;
+ num_connects = 0;
+ httpd_conn_count = 0;
+
+ if (hs != (httpd_server *) 0)
+ {
+ if (hs->listen_fd != -1)
+ fdwatch_add_fd(hs->listen_fd, (void *)0, FDW_READ);
+ }
+
+ /* Main loop */
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ while ((!terminate) || num_connects > 0)
+ {
+ /* Do the fd watch */
+
+ num_ready = fdwatch(tmr_mstimeout(&tv));
+ if (num_ready < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ continue; /* try again */
+ ndbg("fdwatch: %d\n", errno);
+ exit(1);
+ }
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+
+ if (num_ready == 0)
+ {
+ /* No fd's are ready - run the timers */
+
+ tmr_run(&tv);
+ continue;
+ }
+
+ /* Is it a new connection? */
+
+ if (hs != (httpd_server *) 0 && hs->listen_fd != -1 &&
+ fdwatch_check_fd(hs->listen_fd))
+ {
+ if (handle_newconnect(&tv, hs->listen_fd))
+ {
+ /* Go around the loop and do another fdwatch, rather than
+ * dropping through and processing existing connections. New
+ * connections always get priority.
+ */
+
+ continue;
+ }
+ }
+
+ /* Find the connections that need servicing */
+
+ while ((conn =
+ (struct connect_s *) fdwatch_get_next_client_data()) !=
+ (struct connect_s *) - 1)
+ {
+ if (conn == (struct connect_s *) 0)
+ continue;
+
+ hc = conn->hc;
+ if (!fdwatch_check_fd(hc->conn_fd))
+ {
+ /* Something went wrong */
+
+ clear_connection(conn, &tv);
+ }
+ else
+ {
+ switch (conn->conn_state)
+ {
+ case CNST_READING:
+ handle_read(conn, &tv);
+ break;
+ case CNST_SENDING:
+ handle_send(conn, &tv);
+ break;
+ case CNST_LINGERING:
+ handle_linger(conn, &tv);
+ break;
+ }
+ }
+ }
+ tmr_run(&tv);
+ }
+
+ /* The main loop terminated */
+
+ shut_down();
+ ndbg("Exiting\n");
+ exit(0);
+}
+
+
diff --git a/nuttx/netutils/thttpd/timers.h b/nuttx/netutils/thttpd/timers.h
new file mode 100644
index 000000000..e2f3ab57a
--- /dev/null
+++ b/nuttx/netutils/thttpd/timers.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * netutils/thttpd/timers.h
+ * Header file for THTTPD timers package
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Derived from the file of the same name in THTTPD:
+ *
+ * Copyright © 1995,1998,1999,2000 by Jef Poskanzer <jef@mail.acme.com>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_TIMERS_H
+#define __NETUTILS_THTTPD_TIMERS_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <time.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef INFTIM
+# define INFTIM -1
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* ClientData is a random value that tags along with a timer. The client
+ * can use it for whatever, and it gets passed to the callback when the
+ * timer triggers.
+ */
+
+typedef union
+{
+ void *p;
+ int i;
+ long l;
+} ClientData;
+
+/* The TimerProc gets called when the timer expires. It gets passed
+ * the ClientData associated with the timer, and a timeval in case
+ * it wants to schedule another timer.
+ */
+
+typedef void TimerProc(ClientData client_data, struct timeval *nowP);
+
+/* The Timer struct. */
+
+typedef struct TimerStruct
+{
+ TimerProc *timer_proc;
+ ClientData client_data;
+ long msecs;
+ int periodic;
+ struct timeval time;
+ struct TimerStruct *prev;
+ struct TimerStruct *next;
+ int hash;
+} Timer;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+extern ClientData JunkClientData; /* For use when you don't care */
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Initialize the timer package. */
+
+extern void tmr_init(void);
+
+/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */
+
+extern Timer *tmr_create(struct timeval *nowP, TimerProc * timer_proc,
+ ClientData client_data, long msecs, int periodic);
+
+/* Returns a timeout in milliseconds indicating how long until the next timer
+ * triggers. You can just put the call to this routine right in your poll().
+ * Returns INFTIM (-1) if no timers are pending.
+ */
+
+extern long tmr_mstimeout(struct timeval *nowP);
+
+/* Run the list of timers. Your main program needs to call this every so often. */
+
+extern void tmr_run(struct timeval *nowP);
+
+/* Deschedule a timer. Note that non-periodic timers are automatically
+ * descheduled when they run, so you don't have to call this on them.
+ */
+
+extern void tmr_cancel(Timer *timer);
+
+/* Clean up the timers package, freeing any unused storage. */
+
+extern void tmr_cleanup(void);
+
+/* Cancel all timers and free storage, usually in preparation for exitting. */
+
+extern void tmr_destroy(void);
+
+/* Generate debugging statistics syslog message. */
+
+#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
+extern void tmr_logstats(long secs);
+#else
+# define tmr_logstats(secs)
+#endif
+
+#endif /* __NETUTILS_THTTPD_TIMERS_H */
+
diff --git a/nuttx/netutils/thttpd/version.h b/nuttx/netutils/thttpd/version.h
new file mode 100644
index 000000000..d3e56eaeb
--- /dev/null
+++ b/nuttx/netutils/thttpd/version.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * netutils/thttpd/version.h
+ * Version definitions for THTTPD
+ *
+ * Based on version.h by Jef Poskanser which contained no copyright information.
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NETUTILS_THTTPD_VERSION_H
+#define __NETUTILS_THTTPD_VERSION_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SERVER_SOFTWARE "thttpd/2.25b 29dec2003-NuttX"
+#define SERVER_ADDRESS "http://www.nuttx.org"
+
+#endif /* __NETUTILS_THTTPD_VERSION_H */
+