diff --git a/ChangeLog b/ChangeLog index 6f59da81e1056d05404a4471237e3a440cbf3456..daf3551d7b78ae89fd222cd0fce6412a4d44f476 100644 --- a/ChangeLog +++ b/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/Documentation/NuttX.html b/Documentation/NuttX.html index c8079ed1d45acaca1ebc70371a28c3804cdfda0b..8fa4cc0ad6e9438ac1018a17892e3949b106d4bf 100644 --- a/Documentation/NuttX.html +++ b/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/TODO b/TODO index 28b64ece81b8be21e4dac9bdf34bb65e0fae9305..ec53fd2a957105277ef2dfa00fa511536f23f32c 100644 --- a/TODO +++ b/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/configs/ntosd-dm320/defconfig b/configs/ntosd-dm320/defconfig index e3f9022bc06b75a7bdbb6cacd9b2ba9a5408fc0f..b3576fd5ac856310459cb6d790e0e723b228cfa3 100644 --- a/configs/ntosd-dm320/defconfig +++ b/configs/ntosd-dm320/defconfig @@ -291,6 +291,18 @@ CONFIG_NET_BROADCAST=n 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 diff --git a/configs/ntosd-dm320/netconfig b/configs/ntosd-dm320/netconfig index 655ee7d38ad44eabe5ef0d84b3b5af11e036db9d..050196ee5a72812fe5fd2a63dbccfcc661110f05 100644 --- a/configs/ntosd-dm320/netconfig +++ b/configs/ntosd-dm320/netconfig @@ -292,6 +292,18 @@ CONFIG_NET_BROADCAST=n 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 diff --git a/configs/sim/defconfig b/configs/sim/defconfig index 3f80ded189a45acf073a8d3711bd10d3ba3db545..2d959fbcf3f189ef972c7a07235f8c9c08c8195b 100644 --- a/configs/sim/defconfig +++ b/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/configs/sim/netconfig b/configs/sim/netconfig index 296389aec0ed08d5350ac7385cca3c97f5d6d642..2cdea0a6133e174bd546f42ab2c78c378f40ed55 100644 --- a/configs/sim/netconfig +++ b/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/drivers/net/dm90x0.c b/drivers/net/dm90x0.c index 5efca07f4fb03127704c2c540b87b98a1f6422d7..0df832e8f0b0e5d7e4fb398b90bfc726121ed957 100644 --- a/drivers/net/dm90x0.c +++ b/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/examples/uip/main.c b/examples/uip/main.c index e78634a5a95f2bda9b8616bb2d3e18e104168e61..951cde539d2c32e763c10b0685d5762567c813ae 100644 --- a/examples/uip/main.c +++ b/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/include/net/uip/httpd.h b/include/net/uip/httpd.h index ef21cc6ba9b74bfe09a31374dffa52b75d83f1df..44d4d8f4ae0a095fa54cf8a72e2c7604036609c8 100644 --- a/include/net/uip/httpd.h +++ b/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/include/net/uip/uip-lib.h b/include/net/uip/uip-lib.h index 3f6c9860dfe7660cb2e8e64bd98f678845f8a181..d5799ee56ed58de719d0c9724bbbd1ed8cd5eb80 100644 --- a/include/net/uip/uip-lib.h +++ b/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/netutils/Makefile b/netutils/Makefile index 6d8132f77d0873f5c1b02fe2ff8bb63b54893282..4e355ab7ff639b70a68d58a394d2c001fffc6118 100644 --- a/netutils/Makefile +++ b/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/netutils/uiplib/Make.defs b/netutils/uiplib/Make.defs index d8b8ac600df6dc804b0e13bdd92b615c9b76aa42..8acb0218d95f9bcb3d06b428046cf1d116d2bba5 100644 --- a/netutils/uiplib/Make.defs +++ b/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/netutils/uiplib/uip-gethostaddr.c b/netutils/uiplib/uip-gethostaddr.c index a8d36efac4211d90173915ce6126d5c5aa05ed12..732721b10153ec8d1662adf4904ca2e31339b1a0 100644 --- a/netutils/uiplib/uip-gethostaddr.c +++ b/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/netutils/uiplib/uip-getmacaddr.c b/netutils/uiplib/uip-getmacaddr.c index a8f9361139ec7de11d5cdcfe7ffa61dcae0b8c38..9e7a368ab419d12ec94c133095eae821a58db0ae 100644 --- a/netutils/uiplib/uip-getmacaddr.c +++ b/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/netutils/uiplib/uip-server.c b/netutils/uiplib/uip-server.c new file mode 100644 index 0000000000000000000000000000000000000000..aa0ea5b11dd83fc9bf68e5cbaec22598be8aa8f5 --- /dev/null +++ b/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, ¶m) < 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/netutils/uiplib/uip-setdraddr.c b/netutils/uiplib/uip-setdraddr.c index 3b15a9ca9d71fec84bf51d4b7d4dbf479744e9db..e8ab142ec5da2829077685a033d55ad840321926 100644 --- a/netutils/uiplib/uip-setdraddr.c +++ b/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/netutils/uiplib/uip-sethostaddr.c b/netutils/uiplib/uip-sethostaddr.c index 4a0b979bc105f7eec23a2be972475a8dd9214e7c..6247184ba6b34ca1ebc782c7d3c004f3a14c4bcf 100644 --- a/netutils/uiplib/uip-sethostaddr.c +++ b/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/netutils/uiplib/uip-setmacaddr.c b/netutils/uiplib/uip-setmacaddr.c index b02e204ce112b48621416b7b12c92456e1d6fb19..4b1e675300f95288748c6fd0d6a3ea722564f4e7 100644 --- a/netutils/uiplib/uip-setmacaddr.c +++ b/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/netutils/uiplib/uip-setnetmask.c b/netutils/uiplib/uip-setnetmask.c index 56e579ef3f29c218542c0e6e4da179718a62a446..ff70e5a376e02cec206733e2cfb6eed63664a410 100644 --- a/netutils/uiplib/uip-setnetmask.c +++ b/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/netutils/webserver/httpd-cgi.c b/netutils/webserver/httpd-cgi.c index 1c7965374e43f9cdf9e604c43b372b482e57eb4b..e93aff1be4c003fb882694549680822ea3361600 100644 --- a/netutils/webserver/httpd-cgi.c +++ b/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/netutils/webserver/httpd.c b/netutils/webserver/httpd.c index 57e60f8723042c30e3e5da90ed60e7dcfb532ca3..2db3436d78932b02eb299613bc2ce58bfc8f4053 100644 --- a/netutils/webserver/httpd.c +++ b/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/netutils/webserver/httpd.h b/netutils/webserver/httpd.h index b256c1dd16fa4a6ff9b298daec23f3244ebfb1e4..cf067f8078ab6583d7c90606ab234cb4286b4899 100644 --- a/netutils/webserver/httpd.h +++ b/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 */