summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-11-19 18:17:23 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2007-11-19 18:17:23 +0000
commitbefc37ada0b901ad7c315e4089976508396d496b (patch)
tree44818265dc09577601c19bf81b3576109f31a534
parent6f5479c267e1ed09e85461464ae73b4cbfd3d486 (diff)
downloadnuttx-befc37ada0b901ad7c315e4089976508396d496b.tar.gz
nuttx-befc37ada0b901ad7c315e4089976508396d496b.tar.bz2
nuttx-befc37ada0b901ad7c315e4089976508396d496b.zip
uIP webserver now uses listen/accept
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@386 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/Documentation/NuttX.html4
-rw-r--r--nuttx/TODO21
-rw-r--r--nuttx/configs/ntosd-dm320/defconfig12
-rw-r--r--nuttx/configs/ntosd-dm320/netconfig12
-rw-r--r--nuttx/configs/sim/defconfig12
-rw-r--r--nuttx/configs/sim/netconfig12
-rw-r--r--nuttx/drivers/net/dm90x0.c4
-rw-r--r--nuttx/examples/uip/main.c6
-rw-r--r--nuttx/include/net/uip/httpd.h25
-rw-r--r--nuttx/include/net/uip/uip-lib.h28
-rw-r--r--nuttx/netutils/Makefile6
-rw-r--r--nuttx/netutils/uiplib/Make.defs2
-rw-r--r--nuttx/netutils/uiplib/uip-gethostaddr.c2
-rw-r--r--nuttx/netutils/uiplib/uip-getmacaddr.c2
-rw-r--r--nuttx/netutils/uiplib/uip-server.c191
-rw-r--r--nuttx/netutils/uiplib/uip-setdraddr.c2
-rw-r--r--nuttx/netutils/uiplib/uip-sethostaddr.c2
-rw-r--r--nuttx/netutils/uiplib/uip-setmacaddr.c2
-rw-r--r--nuttx/netutils/uiplib/uip-setnetmask.c2
-rw-r--r--nuttx/netutils/webserver/httpd-cgi.c2
-rw-r--r--nuttx/netutils/webserver/httpd.c218
-rw-r--r--nuttx/netutils/webserver/httpd.h53
23 files changed, 490 insertions, 132 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 6f59da81e..daf3551d7 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -225,3 +225,5 @@
recv buffering issues, but this is part of a larger buffering issue.
* Basic server functionality verified: listen(), accept()
* Fix DM90x0 driver problem that caused TX overruns
+ * Add strncmp()
+
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index c8079ed1d..8fa4cc0ad 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -355,7 +355,8 @@ is available that be used to build a NuttX-compatible arm-elf toolchain.</blockq
</pre>
<p><b>DM320 (ARM9)</b>
This build for the ARM9 target includes a signficant subset of OS
- features, ethernet driver and full TCP/IP stack (via uIP). (11/8/07)
+ features, ethernet driver and full TCP/IP, UDP and (minimal) ICMP
+ stacks (via uIP). (11/8/07)
</p>
<pre>
text data bss dec hex filename
@@ -681,6 +682,7 @@ Other memory:
recv buffering issues, but this is part of a larger buffering issue.
* Basic server functionality verified: listen(), accept()
* Fix DM90x0 driver problem that caused TX overruns
+ * Add strncmp()
</pre></ul>
<table width ="100%">
diff --git a/nuttx/TODO b/nuttx/TODO
index 28b64ece8..ec53fd2a9 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -31,21 +31,14 @@ o C++ Support
o Network
- Did not implement send() and sendto() timeouts. Option is setable via setsockopt,
but is not implemented.
-- netutils/webserver netutils/telnetd (and maybe others) are seriously broken.
+- netutils/telnetd (and maybe others) are seriously broken.
Need to be re-written to use listen() and accept()
- Should implement SOCK_RAW
-- listen() and accept() are untested.
- accept() and recvfrom() need to return connection address
- Performance Improvements (uIP is not very fast):
-- Improve performance by queing TX operations
- Add simple buffer management. CONFIG_NET_BUFFERS
- (1) On write, queue buffer for output get a new buffer for the socket (waiting if
- nececcesary
- (2) Copy buffer structure into uip_driver_structure when driver requests write
- data
- (3) Extra read buffers will be necessary to buffer TCP data when there is no recv
- in place to accept the data. At present, received data is not ACKed, but is
- eventually lost in this case.
+- Extra read buffers will be necessary to buffer TCP data when there is no recv
+ in place to accept the data. At present, received data is not ACKed, but is
+ eventually lost in this case.
- Improve performance by stimulating the driver to accept new TX data before the
next polling interval.
@@ -57,7 +50,11 @@ o Network
poll on TCP connections connect on the network supported by the driver; UDP
polling should respond with TX data only if the UDP packet is intended for the
the network supported by the driver.
- (2) If there were multiple drivers, polling would occur at double the rate.
+ (2) If there were multiple drivers, polling would occur at double the rate.i
+ Fix by using bound IP address in TCP connection (lipaddr) and verifying that it
+ is in the subnet served by the driver.
+- uIP/Socket callback logic is not thread safe. This means that a socket cannot be
+ used concurrently by two threads. Minimal fix: Add mutex to support exclusion.
o USB
- Implement USB device support
diff --git a/nuttx/configs/ntosd-dm320/defconfig b/nuttx/configs/ntosd-dm320/defconfig
index e3f9022bc..b3576fd5a 100644
--- a/nuttx/configs/ntosd-dm320/defconfig
+++ b/nuttx/configs/ntosd-dm320/defconfig
@@ -292,6 +292,18 @@ CONFIG_NET_DHCP_LIGHT=n
CONFIG_NET_RESOLV_ENTRIES=4
#
+# Settings for examples/uip
+CONFIG_EXAMPLE_UIP_IPADDR=(10<<24|0<<16|0<<8|2)
+CONFIG_EXAMPLE_UIP_DRIPADDR=(10<<24|0<<16|0<<8|1)
+CONFIG_EXAMPLE_UIP_NETMASK=(255<<24|255<<16|255<<8|0)
+CONFIG_EXAMPLE_UIP_SMTP=n
+CONFIG_EXAMPLE_UIP_TELNETD=n
+CONFIG_EXAMPLE_UIP_WEBSERVER=y
+CONFIG_EXAMPLE_UIP_DHCPC=n
+CONFIG_EXAMPLE_UIP_RESOLV=n
+CONFIG_EXAMPLE_UIP_WEBCLIENT=n
+
+#
# Settings for examples/nettest
CONFIG_EXAMPLE_NETTEST_SERVER=n
CONFIG_EXAMPLE_NETTEST_PERFORMANCE=n
diff --git a/nuttx/configs/ntosd-dm320/netconfig b/nuttx/configs/ntosd-dm320/netconfig
index 655ee7d38..050196ee5 100644
--- a/nuttx/configs/ntosd-dm320/netconfig
+++ b/nuttx/configs/ntosd-dm320/netconfig
@@ -293,6 +293,18 @@ CONFIG_NET_DHCP_LIGHT=n
CONFIG_NET_RESOLV_ENTRIES=4
#
+# Settings for examples/uip
+CONFIG_EXAMPLE_UIP_IPADDR=(10<<24|0<<16|0<<8|2)
+CONFIG_EXAMPLE_UIP_DRIPADDR=(10<<24|0<<16|0<<8|1)
+CONFIG_EXAMPLE_UIP_NETMASK=(255<<24|255<<16|255<<8|0)
+CONFIG_EXAMPLE_UIP_SMTP=n
+CONFIG_EXAMPLE_UIP_TELNETD=n
+CONFIG_EXAMPLE_UIP_WEBSERVER=y
+CONFIG_EXAMPLE_UIP_DHCPC=n
+CONFIG_EXAMPLE_UIP_RESOLV=n
+CONFIG_EXAMPLE_UIP_WEBCLIENT=n
+
+#
# Settings for examples/nettest
CONFIG_EXAMPLE_NETTEST_SERVER=n
CONFIG_EXAMPLE_NETTEST_PERFORMANCE=n
diff --git a/nuttx/configs/sim/defconfig b/nuttx/configs/sim/defconfig
index 3f80ded18..2d959fbcf 100644
--- a/nuttx/configs/sim/defconfig
+++ b/nuttx/configs/sim/defconfig
@@ -258,12 +258,12 @@ CONFIG_NET_RESOLV_ENTRIES=4
CONFIG_EXAMPLE_UIP_IPADDR=(192<<24|168<<16|0<<8|128)
CONFIG_EXAMPLE_UIP_DRIPADDR=(192<<24|168<<16|0<<8|1)
CONFIG_EXAMPLE_UIP_NETMASK=(255<<24|255<<16|255<<8|0)
-#CONFIG_EXAMPLE_UIP_SMTP=
-#CONFIG_EXAMPLE_UIP_TELNETD=
-#CONFIG_EXAMPLE_UIP_WEBSERVER=
-CONFIG_EXAMPLE_UIP_DHCPC=y
-#CONFIG_EXAMPLE_UIP_RESOLV=
-#CONFIG_EXAMPLE_UIP_WEBCLIENT=
+CONFIG_EXAMPLE_UIP_SMTP=n
+CONFIG_EXAMPLE_UIP_TELNETD=n
+CONFIG_EXAMPLE_UIP_WEBSERVER=y
+CONFIG_EXAMPLE_UIP_DHCPC=n
+CONFIG_EXAMPLE_UIP_RESOLV=n
+CONFIG_EXAMPLE_UIP_WEBCLIENT=n
#
# Settings for examples/nettest
diff --git a/nuttx/configs/sim/netconfig b/nuttx/configs/sim/netconfig
index 296389aec..2cdea0a61 100644
--- a/nuttx/configs/sim/netconfig
+++ b/nuttx/configs/sim/netconfig
@@ -259,12 +259,12 @@ CONFIG_NET_RESOLV_ENTRIES=4
CONFIG_EXAMPLE_UIP_IPADDR=(192<<24|168<<16|0<<8|128)
CONFIG_EXAMPLE_UIP_DRIPADDR=(192<<24|168<<16|0<<8|1)
CONFIG_EXAMPLE_UIP_NETMASK=(255<<24|255<<16|255<<8|0)
-#CONFIG_EXAMPLE_UIP_SMTP=
-#CONFIG_EXAMPLE_UIP_TELNETD=
-#CONFIG_EXAMPLE_UIP_WEBSERVER=
-CONFIG_EXAMPLE_UIP_DHCPC=y
-#CONFIG_EXAMPLE_UIP_RESOLV=
-#CONFIG_EXAMPLE_UIP_WEBCLIENT=
+CONFIG_EXAMPLE_UIP_SMTP=n
+CONFIG_EXAMPLE_UIP_TELNETD=n
+CONFIG_EXAMPLE_UIP_WEBSERVER=y
+CONFIG_EXAMPLE_UIP_DHCPC=n
+CONFIG_EXAMPLE_UIP_RESOLV=n
+CONFIG_EXAMPLE_UIP_WEBCLIENT=n
#
# Settings for examples/nettest
diff --git a/nuttx/drivers/net/dm90x0.c b/nuttx/drivers/net/dm90x0.c
index 5efca07f4..0df832e8f 100644
--- a/nuttx/drivers/net/dm90x0.c
+++ b/nuttx/drivers/net/dm90x0.c
@@ -1357,7 +1357,9 @@ static int dm9x_ifup(struct uip_driver_s *dev)
uint8 netstatus;
int i;
- dbg("Bringing the interface up\n" );
+ dbg("Bringing up: %d.%d.%d.%d\n",
+ dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
+ (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 );
/* Initilize DM90x0 chip */
diff --git a/nuttx/examples/uip/main.c b/nuttx/examples/uip/main.c
index e78634a5a..951cde539 100644
--- a/nuttx/examples/uip/main.c
+++ b/nuttx/examples/uip/main.c
@@ -119,16 +119,16 @@ int user_start(int argc, char *argv[])
#if !defined(CONFIG_EXAMPLE_UIP_DHCPC)
struct in_addr addr;
#endif
-#if defined(CONFIG_EXAMPLE_UIP_DHCPC) || !defined(CONFIG_ARCH_SIM)
+#if defined(CONFIG_EXAMPLE_UIP_DHCPC) || defined(CONFIG_EXAMPLE_UIP_NOMAC)
uint8 mac[IFHWADDRLEN];
#endif
#if defined(CONFIG_EXAMPLE_UIP_DHCPC) || defined(CONFIG_EXAMPLE_UIP_SMTP)
void *handle;
#endif
-/* Most embedded network interfaces must have a software assigned MAC */
+/* Many embedded network interfaces must have a software assigned MAC */
-#if !defined(CONFIG_ARCH_SIM)
+#ifdef CONFIG_EXAMPLE_UIP_NOMAC
mac[0] = 0x00;
mac[1] = 0xe0;
mac[2] = 0xb0;
diff --git a/nuttx/include/net/uip/httpd.h b/nuttx/include/net/uip/httpd.h
index ef21cc6ba..44d4d8f4a 100644
--- a/nuttx/include/net/uip/httpd.h
+++ b/nuttx/include/net/uip/httpd.h
@@ -1,11 +1,19 @@
-/* httpd.h
+/****************************************************************************
+ * net/uip/httpd.h
*
- * Copyright (c) 2001-2005, Adam Dunkels.
- * All rights reserved.
+ * Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Based on uIP which also has a BSD style license:
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ * Copyright (c) 2001-2005, Adam Dunkels.
+ * 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
@@ -26,13 +34,22 @@
* 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 _NET_UIP_HTTPD_H
#define _NET_UIP_HTTPD_H
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
#include <sys/types.h>
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
extern void httpd_init(void);
extern int httpd_listen(void);
diff --git a/nuttx/include/net/uip/uip-lib.h b/nuttx/include/net/uip/uip-lib.h
index 3f6c9860d..d5799ee56 100644
--- a/nuttx/include/net/uip/uip-lib.h
+++ b/nuttx/include/net/uip/uip-lib.h
@@ -42,9 +42,33 @@
#ifndef __UIPLIB_H__
#define __UIPLIB_H__
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
#include <nuttx/config.h>
+#include <sched.h>
#include <netinet/in.h>
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* SOCK_DGRAM is the preferred socket type to use when we just want a
+ * socket for performing drive ioctls. However, we can't use SOCK_DRAM
+ * if UDP is disabled.
+ */
+
+#ifdef CONFIG_NET_UDP
+# define UIPLIB_SOCK_IOCTL SOCK_DGRAM
+#else
+# define UIPLIB_SOCK_IOCTL SOCK_STREAM
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
/* Convert a textual representation of an IP address to a numerical representation.
*
* This function takes a textual representation of an IP address in
@@ -80,4 +104,8 @@ extern int uip_setdraddr(const char *ifname, const struct in_addr *addr);
extern int uip_setnetmask(const char *ifname, const struct in_addr *addr);
#endif
+/* Generic server logic */
+
+extern void uip_server(uint16 portno, main_t handler, int stacksize);
+
#endif /* __UIPLIB_H__ */
diff --git a/nuttx/netutils/Makefile b/nuttx/netutils/Makefile
index 6d8132f77..4e355ab7f 100644
--- a/nuttx/netutils/Makefile
+++ b/nuttx/netutils/Makefile
@@ -39,12 +39,14 @@ MKDEP = $(TOPDIR)/tools/mkdeps.sh
ifeq ($(CONFIG_NET),y)
include uiplib/Make.defs
-include dhcpc/Make.defs
-include resolv/Make.defs
include smtp/Make.defs
include telnetd/Make.defs
include webclient/Make.defs
include webserver/Make.defs
+ifeq ($(CONFIG_NET_UDP),y)
+include dhcpc/Make.defs
+include resolv/Make.defs
+endif
include Make.str
endif
diff --git a/nuttx/netutils/uiplib/Make.defs b/nuttx/netutils/uiplib/Make.defs
index d8b8ac600..8acb0218d 100644
--- a/nuttx/netutils/uiplib/Make.defs
+++ b/nuttx/netutils/uiplib/Make.defs
@@ -35,4 +35,4 @@
UIPLIB_ASRCS =
UIPLIB_CSRCS = uiplib.c uip-setmacaddr.c uip-getmacaddr.c uip-sethostaddr.c \
- uip-gethostaddr.c uip-setdraddr.c uip-setnetmask.c
+ uip-gethostaddr.c uip-setdraddr.c uip-setnetmask.c uip-server.c
diff --git a/nuttx/netutils/uiplib/uip-gethostaddr.c b/nuttx/netutils/uiplib/uip-gethostaddr.c
index a8d36efac..732721b10 100644
--- a/nuttx/netutils/uiplib/uip-gethostaddr.c
+++ b/nuttx/netutils/uiplib/uip-gethostaddr.c
@@ -81,7 +81,7 @@ int uip_gethostaddr(const char *ifname, struct in_addr *addr)
int ret = ERROR;
if (ifname && addr)
{
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/uiplib/uip-getmacaddr.c b/nuttx/netutils/uiplib/uip-getmacaddr.c
index a8f936113..9e7a368ab 100644
--- a/nuttx/netutils/uiplib/uip-getmacaddr.c
+++ b/nuttx/netutils/uiplib/uip-getmacaddr.c
@@ -75,7 +75,7 @@ int uip_getmacaddr(const char *ifname, uint8 *macaddr)
{
/* Get a socket (only so that we get access to the INET subsystem) */
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/uiplib/uip-server.c b/nuttx/netutils/uiplib/uip-server.c
new file mode 100644
index 000000000..aa0ea5b11
--- /dev/null
+++ b/nuttx/netutils/uiplib/uip-server.c
@@ -0,0 +1,191 @@
+/****************************************************************************
+ * netutils/uiplib/uip-server.c
+ *
+ * Copyright (C) 2007 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 Gregory Nutt 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <net/uip/uip-lib.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#define errno *get_errno_ptr()
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: uip_server
+ *
+ * Description:
+ * Implement basic server logic
+ *
+ * Parameters:
+ * portno The port to listen on (in network byte order)
+ * handler The entrypoint of the task to spawn when a new connection is
+ * accepted.
+ * stacksize The stack size needed by the spawned task
+ *
+ * Return:
+ * Does not return unless an error occurs.
+ *
+ ****************************************************************************/
+
+void uip_server(uint16 portno, main_t handler, int stacksize)
+{
+ struct sockaddr_in myaddr;
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ struct linger ling;
+#endif
+ struct sched_param param;
+ socklen_t addrlen;
+ const char *argv[2];
+ int listensd;
+ int acceptsd;
+#ifdef CONFIG_NET_HAVE_REUSEADDR
+ int optval;
+#endif
+
+ /* Create a new TCP socket to use to listen for connections */
+
+ listensd = socket(PF_INET, SOCK_STREAM, 0);
+ if (listensd < 0)
+ {
+ dbg("socket failure: %d\n", errno);
+ return;
+ }
+
+ /* Set socket to reuse address */
+
+#ifdef CONFIG_NET_HAVE_REUSEADDR
+ optval = 1;
+ if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
+ {
+ dbg("setsockopt SO_REUSEADDR failure: %d\n", errno);
+ goto errout_with_socket;
+ }
+#endif
+
+ /* Bind the socket to a local address */
+
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_port = portno;
+ myaddr.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
+ {
+ dbg("bind failure: %d\n", errno);
+ goto errout_with_socket;
+ }
+
+ /* Listen for connections on the bound TCP socket */
+
+ if (listen(listensd, 5) < 0)
+ {
+ dbg("listen failure %d\n", errno);
+ goto errout_with_socket;
+ }
+
+ /* Begin accepting connections */
+
+ dbg("Accepting connections on port %d\n", ntohs(portno));
+ for (;;)
+ {
+ addrlen = sizeof(struct sockaddr_in);
+ acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
+ if (acceptsd < 0)
+ {
+ dbg("accept failure: %d\n", errno);
+ break;;
+ }
+ dbg("Connection accepted -- spawning\n");
+
+ /* Configure to "linger" until all data is sent when the socket is closed */
+
+#ifdef CONFIG_NET_HAVE_SOLINGER
+ ling.l_onoff = 1;
+ ling.l_linger = 30; /* timeout is seconds */
+ if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0)
+ {
+ close(acceptsd);
+ dbg("setsockopt SO_LINGER failure: %d\n", errno);
+ break;;
+ }
+#endif
+
+ /* Spawn a thread to handle the connection. The socket descriptor +1 is
+ * provided in as the single argument to the new thread. (The +1 is intended
+ * to handle the valid, zero file descriptor).
+ */
+
+ if (sched_getparam(0, &param) < 0)
+ {
+ close(acceptsd);
+ dbg("sched_getparam failed: %d\n", errno);
+ break;;
+ }
+
+ argv[0] = (char*)(acceptsd + 1);
+ argv[1] = NULL;
+
+ if (task_create("", param.sched_priority, stacksize, handler, argv) < 0)
+ {
+ close(acceptsd);
+ dbg("task_create failed: %d\n", errno);
+ break;;
+ }
+
+ /* We can close our copy of acceptsd now. This file descriptor was dup'ed
+ * by task_create and we no longer need to retain the reference.
+ */
+
+ close(acceptsd);
+ }
+
+errout_with_socket:
+ close(listensd);
+}
diff --git a/nuttx/netutils/uiplib/uip-setdraddr.c b/nuttx/netutils/uiplib/uip-setdraddr.c
index 3b15a9ca9..e8ab142ec 100644
--- a/nuttx/netutils/uiplib/uip-setdraddr.c
+++ b/nuttx/netutils/uiplib/uip-setdraddr.c
@@ -78,7 +78,7 @@ int uip_setdraddr(const char *ifname, const struct in_addr *addr)
int ret = ERROR;
if (ifname && addr)
{
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/uiplib/uip-sethostaddr.c b/nuttx/netutils/uiplib/uip-sethostaddr.c
index 4a0b979bc..6247184ba 100644
--- a/nuttx/netutils/uiplib/uip-sethostaddr.c
+++ b/nuttx/netutils/uiplib/uip-sethostaddr.c
@@ -78,7 +78,7 @@ int uip_sethostaddr(const char *ifname, const struct in_addr *addr)
int ret = ERROR;
if (ifname && addr)
{
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/uiplib/uip-setmacaddr.c b/nuttx/netutils/uiplib/uip-setmacaddr.c
index b02e204ce..4b1e67530 100644
--- a/nuttx/netutils/uiplib/uip-setmacaddr.c
+++ b/nuttx/netutils/uiplib/uip-setmacaddr.c
@@ -86,7 +86,7 @@ int uip_setmacaddr(const char *ifname, const uint8 *macaddr)
{
/* Get a socket (only so that we get access to the INET subsystem) */
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/uiplib/uip-setnetmask.c b/nuttx/netutils/uiplib/uip-setnetmask.c
index 56e579ef3..ff70e5a37 100644
--- a/nuttx/netutils/uiplib/uip-setnetmask.c
+++ b/nuttx/netutils/uiplib/uip-setnetmask.c
@@ -78,7 +78,7 @@ int uip_setnetmask(const char *ifname, const struct in_addr *addr)
int ret = ERROR;
if (ifname && addr)
{
- int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ int sockfd = socket(PF_INET, UIPLIB_SOCK_IOCTL, 0);
if (sockfd >= 0)
{
struct ifreq req;
diff --git a/nuttx/netutils/webserver/httpd-cgi.c b/nuttx/netutils/webserver/httpd-cgi.c
index 1c7965374..e93aff1be 100644
--- a/nuttx/netutils/webserver/httpd-cgi.c
+++ b/nuttx/netutils/webserver/httpd-cgi.c
@@ -125,7 +125,7 @@ static void file_stats(struct httpd_state *pstate, char *ptr)
char buffer[16];
char *pcount = strchr(ptr, ' ') + 1;
snprintf(buffer, 16, "%5u", httpd_fs_count(pcount));
- (void)send(pstate->sockout, buffer, strlen(buffer), 0);
+ (void)send(pstate->sockfd, buffer, strlen(buffer), 0);
}
#endif
diff --git a/nuttx/netutils/webserver/httpd.c b/nuttx/netutils/webserver/httpd.c
index 57e60f872..2db3436d7 100644
--- a/nuttx/netutils/webserver/httpd.c
+++ b/nuttx/netutils/webserver/httpd.c
@@ -45,11 +45,17 @@
* Included Files
****************************************************************************/
-#include <stdlib.h>
+#include <nuttx/config.h>
+
#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <debug.h>
#include <net/uip/uip.h>
+#include <net/uip/uip-lib.h>
#include <net/uip/httpd.h>
#include "httpd.h"
@@ -60,9 +66,6 @@
* Definitions
****************************************************************************/
-#define STATE_WAITING 0
-#define STATE_OUTPUT 1
-
#define ISO_nl 0x0a
#define ISO_space 0x20
#define ISO_bang 0x21
@@ -71,21 +74,50 @@
#define ISO_slash 0x2f
#define ISO_colon 0x3a
-#define SEND_STR(psock, str) psock_send(psock, str, strlen(str))
+#define CONFIG_NETUTILS_HTTPD_DUMPBUFFER 1
/****************************************************************************
* Private Functions
****************************************************************************/
-static inline int send_file(struct httpd_state *pstate)
+#ifdef CONFIG_NETUTILS_HTTPD_DUMPBUFFER
+static void httpd_dumpbuffer(struct httpd_state *pstate, ssize_t nbytes)
{
- return send(pstate->sockout, pstate->file.data, pstate->file.len, 0);
-}
+#ifdef CONFIG_DEBUG
+ char line[128];
+ int ch;
+ int i;
+ int j;
-static inline int send_part_of_file(struct httpd_state *pstate)
-{
- return send(pstate->sockout, pstate->file.data, pstate->len, 0);
+ for (i = 0; i < nbytes; i += 16)
+ {
+ sprintf(line, "%04x: ", i);
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ sprintf(&line[strlen(line)], "%02x ", pstate->ht_buffer[i+j] );
+ }
+ else
+ {
+ strcpy(&line[strlen(line)], " ");
+ }
+ }
+ for ( j = 0; j < 16; j++)
+ {
+ if (i + j < nbytes)
+ {
+ ch = pstate->ht_buffer[i+j];
+ sprintf(&line[strlen(line)], "%c", ch >= 0x20 && ch <= 0x7e ? ch : '.');
+ }
+ }
+ dbg("%s", line);
+ }
+#endif
}
+#else
+# define httpd_dumpbuffer(pstate,nbytes)
+#endif
static void next_scriptstate(struct httpd_state *pstate)
{
@@ -95,35 +127,40 @@ static void next_scriptstate(struct httpd_state *pstate)
pstate->scriptptr = p;
}
-static void handle_script(struct httpd_state *pstate, struct uip_conn *conn)
+static void handle_script(struct httpd_state *pstate)
{
char *ptr;
while(pstate->file.len > 0) {
- /* Check if we should start executing a script. */
+ /* Check if we should start executing a script */
+
if (*pstate->file.data == ISO_percent &&
*(pstate->file.data + 1) == ISO_bang) {
pstate->scriptptr = pstate->file.data + 3;
pstate->scriptlen = pstate->file.len - 3;
- if (*(pstate->scriptptr - 1) == ISO_colon) {
- httpd_fs_open(pstate->scriptptr + 1, &pstate->file);
- send_file(pstate);
- } else {
- httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr);
- }
+ if (*(pstate->scriptptr - 1) == ISO_colon)
+ {
+ httpd_fs_open(pstate->scriptptr + 1, &pstate->file);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
+ }
+ else
+ {
+ httpd_cgi(pstate->scriptptr)(pstate, pstate->scriptptr);
+ }
next_scriptstate(pstate);
/* The script is over, so we reset the pointers and continue
- sending the rest of the file. */
+ sending the rest of the file */
pstate->file.data = pstate->scriptptr;
pstate->file.len = pstate->scriptlen;
+
} else {
/* See if we find the start of script marker in the block of HTML
- to be sent. */
+ to be sent */
- if (pstate->file.len > uip_mss(conn)) {
- pstate->len = uip_mss(conn);
+ if (pstate->file.len > HTTPD_IOBUFFER_SIZE) {
+ pstate->len = HTTPD_IOBUFFER_SIZE;
} else {
pstate->len = pstate->file.len;
}
@@ -136,11 +173,11 @@ static void handle_script(struct httpd_state *pstate, struct uip_conn *conn)
if (ptr != NULL &&
ptr != pstate->file.data) {
pstate->len = (int)(ptr - pstate->file.data);
- if (pstate->len >= uip_mss(conn)) {
- pstate->len = uip_mss(conn);
+ if (pstate->len >= HTTPD_IOBUFFER_SIZE) {
+ pstate->len = HTTPD_IOBUFFER_SIZE;
}
}
- send_part_of_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->len, 0);
pstate->file.data += pstate->len;
pstate->file.len -= pstate->len;
}
@@ -152,41 +189,41 @@ static int send_headers(struct httpd_state *pstate, const char *statushdr)
char *ptr;
int ret;
- ret = send(pstate->sockout, statushdr, strlen(statushdr), 0);
+ ret = send(pstate->sockfd, statushdr, strlen(statushdr), 0);
ptr = strrchr(pstate->filename, ISO_period);
if (ptr == NULL)
{
- ret = send(pstate->sockout, http_content_type_binary, strlen(http_content_type_binary), 0);
+ ret = send(pstate->sockfd, http_content_type_binary, strlen(http_content_type_binary), 0);
}
else if (strncmp(http_html, ptr, 5) == 0 || strncmp(http_shtml, ptr, 6) == 0)
{
- ret = send(pstate->sockout, http_content_type_html, strlen(http_content_type_html), 0);
+ ret = send(pstate->sockfd, http_content_type_html, strlen(http_content_type_html), 0);
}
else if (strncmp(http_css, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_css, strlen(http_content_type_css), 0);
+ ret = send(pstate->sockfd, http_content_type_css, strlen(http_content_type_css), 0);
}
else if (strncmp(http_png, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_png, strlen(http_content_type_png), 0);
+ ret = send(pstate->sockfd, http_content_type_png, strlen(http_content_type_png), 0);
}
else if (strncmp(http_gif, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_gif, strlen(http_content_type_gif), 0);
+ ret = send(pstate->sockfd, http_content_type_gif, strlen(http_content_type_gif), 0);
}
else if (strncmp(http_jpg, ptr, 4) == 0)
{
- ret = send(pstate->sockout, http_content_type_jpg, strlen(http_content_type_jpg), 0);
+ ret = send(pstate->sockfd, http_content_type_jpg, strlen(http_content_type_jpg), 0);
}
else
{
- ret = send(pstate->sockout, http_content_type_plain, strlen(http_content_type_plain), 0);
+ ret = send(pstate->sockfd, http_content_type_plain, strlen(http_content_type_plain), 0);
}
return ret;
}
-static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
+static void httpd_sendfile(struct httpd_state *pstate)
{
char *ptr;
@@ -195,7 +232,7 @@ static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
httpd_fs_open(http_404_html, &pstate->file);
strcpy(pstate->filename, http_404_html);
send_headers(pstate, http_header_404);
- send_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
}
else
{
@@ -203,75 +240,102 @@ static void handle_output(struct httpd_state *pstate, struct uip_conn *conn)
ptr = strchr(pstate->filename, ISO_period);
if (ptr != NULL && strncmp(ptr, http_shtml, 6) == 0)
{
- handle_script(pstate, conn);
+ handle_script(pstate);
}
else
{
- send_file(pstate);
+ send(pstate->sockfd, pstate->file.data, pstate->file.len, 0);
}
}
}
-static int handle_input(struct httpd_state *pstate)
+static inline int httpd_cmd(struct httpd_state *pstate)
{
ssize_t recvlen;
+ int i;
+
+ /* Get the next HTTP command. We will handle only GET */
- if (recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0) < 0)
+ recvlen = recv(pstate->sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0);
+ if (recvlen < 0)
{
return ERROR;
}
+ httpd_dumpbuffer(pstate, recvlen);
- if (strncmp(pstate->inputbuf, http_get, 4) != 0)
- {
- return ERROR;
- }
+ /* We will handle only GET */
- recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
- if (recvlen < 0)
+ if (strncmp(pstate->ht_buffer, http_get, 4) != 0)
{
return ERROR;
}
- if (pstate->inputbuf[0] != ISO_slash)
- {
- return ERROR;
- }
+ /* Get the name of the file to provide */
- if (pstate->inputbuf[1] == ISO_space)
+ if (pstate->ht_buffer[4] != ISO_slash)
+ {
+ return ERROR;
+ }
+ else if (pstate->ht_buffer[5] == ISO_space)
{
strncpy(pstate->filename, http_index_html, sizeof(pstate->filename));
}
else
{
- pstate->inputbuf[recvlen - 1] = 0;
- strncpy(pstate->filename, &pstate->inputbuf[0], sizeof(pstate->filename));
+ for (i = 5; i < sizeof(pstate->filename) + 5 && pstate->ht_buffer[5] != ISO_space; i++)
+ {
+ pstate->filename[i] = pstate->ht_buffer[i+5];
+ }
}
- pstate->state = STATE_OUTPUT;
+ /* Then send the file */
+
+ httpd_sendfile(pstate);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: httpd_handler
+ *
+ * Description:
+ * Each time a new connection to port 80 is made, a new thread is created
+ * that begins at this entry point. There should be exactly one argument
+ * and it should be the socket descriptor (+1).
+ *
+ ****************************************************************************/
+
+static int httpd_handler(int argc, char *argv[])
+{
+ struct httpd_state *pstate = (struct httpd_state *)malloc(sizeof(struct httpd_state));
+ int sockfd = (int)argv[1] - 1;
+ int ret = ERROR;
+
+ /* Verify that the state structure was successfully allocated */
- while(1)
+ if (pstate)
{
- recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
- if (recvlen < 0)
+ /* Loop processing each HTTP command */
+ do
{
- return ERROR;
- }
+ /* Re-initialize the thread state structure */
- if (strncmp(pstate->inputbuf, http_referer, 8) == 0)
- {
- pstate->inputbuf[recvlen - 2] = 0;
+ memset(pstate, 0, sizeof(struct httpd_state));
+ pstate->sockfd = sockfd;
+
+ /* Then handle the next httpd command */
+
+ ret = httpd_cmd(pstate);
}
- }
+ while (ret == OK);
- return OK;
-}
+ /* End of command processing -- Clean up and exit */
-static void handle_connection(struct httpd_state *pstate, struct uip_conn *conn)
-{
- handle_input(pstate);
- if (pstate->state == STATE_OUTPUT) {
- handle_output(pstate, conn);
+ free(pstate);
}
+
+ /* Exit the task */
+
+ return 0;
}
/****************************************************************************
@@ -288,20 +352,24 @@ static void handle_connection(struct httpd_state *pstate, struct uip_conn *conn)
int httpd_listen(void)
{
-#warning "this is all very broken at the moment"
- return OK;
+ /* Execute httpd_handler on each connection to port 80 */
+
+ uip_server(HTONS(80), httpd_handler, CONFIG_EXAMPLES_UIP_HTTPDSTACKSIZE);
+
+ /* uip_server only returns on errors */
+
+ return ERROR;
}
/****************************************************************************
* Name: httpd_init
*
* Description:
- * This function initializes the web server and should be called at system
- * boot-up.
+ * This function initializes the web server and should be called at system
+ * boot-up.
*
****************************************************************************/
void httpd_init(void)
{
- uip_listen(HTONS(80));
}
diff --git a/nuttx/netutils/webserver/httpd.h b/nuttx/netutils/webserver/httpd.h
index b256c1dd1..cf067f807 100644
--- a/nuttx/netutils/webserver/httpd.h
+++ b/nuttx/netutils/webserver/httpd.h
@@ -1,11 +1,19 @@
-/* httpd.h
+/****************************************************************************
+ * netutils/webserver/httpd.h
*
- * Copyright (c) 2001-2005, Adam Dunkels.
- * All rights reserved.
+ * Copyright (C) 2007 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Based on uIP which also has a BSD style license:
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ * Copyright (c) 2001-2005, Adam Dunkels.
+ * 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
@@ -26,15 +34,33 @@
* 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_WEBSERVER_HTTPD_H
#define _NETUTILS_WEBSERVER_HTTPD_H
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
#include <sys/types.h>
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
#define HTTPD_FS_STATISTICS 1
-#define HTTPD_INBUFFER_SIZE 50
+#define HTTPD_IOBUFFER_SIZE 512
+
+#ifndef CONFIG_EXAMPLES_UIP_HTTPDSTACKSIZE
+# define CONFIG_EXAMPLES_UIP_HTTPDSTACKSIZE 4096
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
struct httpd_fs_file
{
@@ -44,13 +70,10 @@ struct httpd_fs_file
struct httpd_state
{
- unsigned char timer;
- int sockin;
- int sockout;
- char inputbuf[HTTPD_INBUFFER_SIZE];
+ char ht_buffer[HTTPD_IOBUFFER_SIZE];
char filename[20];
- char state;
struct httpd_fs_file file;
+ int sockfd; /* The socket descriptor from accept() */
int len;
char *scriptptr;
int scriptlen;
@@ -58,17 +81,19 @@ struct httpd_state
unsigned short count;
};
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
#ifdef HTTPD_FS_STATISTICS
#if HTTPD_FS_STATISTICS == 1
extern uint16 httpd_fs_count(char *name);
#endif /* HTTPD_FS_STATISTICS */
#endif /* HTTPD_FS_STATISTICS */
-/* file must be allocated by caller and will be filled in
- * by the function.
- */
+/* file must be allocated by caller and will be filled in by the function. */
-int httpd_fs_open(const char *name, struct httpd_fs_file *file);
+int httpd_fs_open(const char *name, struct httpd_fs_file *file);
void httpd_fs_init(void);
#endif /* _NETUTILS_WEBSERVER_HTTPD_H */