uIP webserver now uses listen/accept

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@386 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2007-11-19 18:17:23 +00:00
parent 5698f351b1
commit ca5e8b5998
23 changed files with 494 additions and 136 deletions
+2
View File
@@ -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()
+3 -1
View File
@@ -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%">
+9 -12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+6 -6
View File
@@ -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
+6 -6
View File
@@ -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
+3 -1
View File
@@ -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 */
+3 -3
View File
@@ -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;
+21 -4
View File
@@ -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);
+28
View File
@@ -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__ */
+4 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+191
View File
@@ -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);
}
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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
+147 -79
View File
@@ -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;
if (recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0) < 0)
{
return ERROR;
}
/* Get the next HTTP command. We will handle only GET */
if (strncmp(pstate->inputbuf, http_get, 4) != 0)
{
return ERROR;
}
recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
recvlen = recv(pstate->sockfd, pstate->ht_buffer, HTTPD_IOBUFFER_SIZE, 0);
if (recvlen < 0)
{
return ERROR;
}
httpd_dumpbuffer(pstate, recvlen);
if (pstate->inputbuf[0] != ISO_slash)
{
return ERROR;
}
/* We will handle only GET */
if (pstate->inputbuf[1] == ISO_space)
if (strncmp(pstate->ht_buffer, http_get, 4) != 0)
{
return ERROR;
}
/* Get the name of the file to provide */
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));
}
pstate->state = STATE_OUTPUT;
while(1)
{
recvlen = recv(pstate->sockin, pstate->inputbuf, HTTPD_INBUFFER_SIZE, 0);
if (recvlen < 0)
for (i = 5; i < sizeof(pstate->filename) + 5 && pstate->ht_buffer[5] != ISO_space; i++)
{
return ERROR;
}
if (strncmp(pstate->inputbuf, http_referer, 8) == 0)
{
pstate->inputbuf[recvlen - 2] = 0;
pstate->filename[i] = pstate->ht_buffer[i+5];
}
}
/* Then send the file */
httpd_sendfile(pstate);
return OK;
}
static void handle_connection(struct httpd_state *pstate, struct uip_conn *conn)
/****************************************************************************
* 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[])
{
handle_input(pstate);
if (pstate->state == STATE_OUTPUT) {
handle_output(pstate, conn);
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 */
if (pstate)
{
/* Loop processing each HTTP command */
do
{
/* Re-initialize the thread state structure */
memset(pstate, 0, sizeof(struct httpd_state));
pstate->sockfd = sockfd;
/* Then handle the next httpd command */
ret = httpd_cmd(pstate);
}
while (ret == OK);
/* End of command processing -- Clean up and exit */
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));
}
+39 -14
View File
@@ -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 */