diff options
Diffstat (limited to 'uip/apps')
57 files changed, 5487 insertions, 0 deletions
diff --git a/uip/apps/README b/uip/apps/README new file mode 100644 index 0000000..0096c4e --- /dev/null +++ b/uip/apps/README @@ -0,0 +1,2 @@ +This directory contains a few example applications. They are not all +heavily tested, however. diff --git a/uip/apps/dhcpc/Makefile.dhcpc b/uip/apps/dhcpc/Makefile.dhcpc new file mode 100644 index 0000000..f84c84f --- /dev/null +++ b/uip/apps/dhcpc/Makefile.dhcpc @@ -0,0 +1 @@ +APP_SOURCES += dhcpc.c timer.c diff --git a/uip/apps/dhcpc/dhcpc.c b/uip/apps/dhcpc/dhcpc.c new file mode 100644 index 0000000..ac738e7 --- /dev/null +++ b/uip/apps/dhcpc/dhcpc.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack + * + * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + */ + +#include <stdio.h> +#include <string.h> + +#include "uip.h" +#include "dhcpc.h" +#include "timer.h" +#include "pt.h" + +#define STATE_INITIAL 0 +#define STATE_SENDING 1 +#define STATE_OFFER_RECEIVED 2 +#define STATE_CONFIG_RECEIVED 3 + +static struct dhcpc_state s; + +struct dhcp_msg { + u8_t op, htype, hlen, hops; + u8_t xid[4]; + u16_t secs, flags; + u8_t ciaddr[4]; + u8_t yiaddr[4]; + u8_t siaddr[4]; + u8_t giaddr[4]; + u8_t chaddr[16]; +#ifndef UIP_CONF_DHCP_LIGHT + u8_t sname[64]; + u8_t file[128]; +#endif + u8_t options[312]; +}; + +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPC_SERVER_PORT 67 +#define DHCPC_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23}; +static const u8_t magic_cookie[4] = {99, 130, 83, 99}; +/*---------------------------------------------------------------------------*/ +static u8_t * +add_msg_type(u8_t *optptr, u8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_server_id(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + memcpy(optptr, s.serverid, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_req_ipaddr(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_IPADDR; + *optptr++ = 4; + memcpy(optptr, s.ipaddr, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_req_options(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_LIST; + *optptr++ = 3; + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = DHCP_OPTION_DNS_SERVER; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static u8_t * +add_end(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static void +create_msg(register struct dhcp_msg *m) +{ + m->op = DHCP_REQUEST; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = s.mac_len; + m->hops = 0; + memcpy(m->xid, xid, sizeof(m->xid)); + m->secs = 0; + m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */ + /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/ + memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr)); + memset(m->yiaddr, 0, sizeof(m->yiaddr)); + memset(m->siaddr, 0, sizeof(m->siaddr)); + memset(m->giaddr, 0, sizeof(m->giaddr)); + memcpy(m->chaddr, s.mac_addr, s.mac_len); + memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len); +#ifndef UIP_CONF_DHCP_LIGHT + memset(m->sname, 0, sizeof(m->sname)); + memset(m->file, 0, sizeof(m->file)); +#endif + + memcpy(m->options, magic_cookie, sizeof(magic_cookie)); +} +/*---------------------------------------------------------------------------*/ +static void +send_discover(void) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPDISCOVER); + end = add_req_options(end); + end = add_end(end); + + uip_send(uip_appdata, end - (u8_t *)uip_appdata); +} +/*---------------------------------------------------------------------------*/ +static void +send_request(void) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPREQUEST); + end = add_server_id(end); + end = add_req_ipaddr(end); + end = add_end(end); + + uip_send(uip_appdata, end - (u8_t *)uip_appdata); +} +/*---------------------------------------------------------------------------*/ +static u8_t +parse_options(u8_t *optptr, int len) +{ + u8_t *end = optptr + len; + u8_t type = 0; + + while(optptr < end) { + switch(*optptr) { + case DHCP_OPTION_SUBNET_MASK: + memcpy(s.netmask, optptr + 2, 4); + break; + case DHCP_OPTION_ROUTER: + memcpy(s.default_router, optptr + 2, 4); + break; + case DHCP_OPTION_DNS_SERVER: + memcpy(s.dnsaddr, optptr + 2, 4); + break; + case DHCP_OPTION_MSG_TYPE: + type = *(optptr + 2); + break; + case DHCP_OPTION_SERVER_ID: + memcpy(s.serverid, optptr + 2, 4); + break; + case DHCP_OPTION_LEASE_TIME: + memcpy(s.lease_time, optptr + 2, 4); + break; + case DHCP_OPTION_END: + return type; + } + + optptr += optptr[1] + 2; + } + return type; +} +/*---------------------------------------------------------------------------*/ +static u8_t +parse_msg(void) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + if(m->op == DHCP_REPLY && + memcmp(m->xid, xid, sizeof(xid)) == 0 && + memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) { + memcpy(s.ipaddr, m->yiaddr, 4); + return parse_options(&m->options[4], uip_datalen()); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_dhcp(void)) +{ + PT_BEGIN(&s.pt); + + /* try_again:*/ + s.state = STATE_SENDING; + s.ticks = CLOCK_SECOND; + + do { + send_discover(); + timer_set(&s.timer, s.ticks); + PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); + + if(uip_newdata() && parse_msg() == DHCPOFFER) { + s.state = STATE_OFFER_RECEIVED; + break; + } + + if(s.ticks < CLOCK_SECOND * 60) { + s.ticks *= 2; + } + } while(s.state != STATE_OFFER_RECEIVED); + + s.ticks = CLOCK_SECOND; + + do { + send_request(); + timer_set(&s.timer, s.ticks); + PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); + + if(uip_newdata() && parse_msg() == DHCPACK) { + s.state = STATE_CONFIG_RECEIVED; + break; + } + + if(s.ticks <= CLOCK_SECOND * 10) { + s.ticks += CLOCK_SECOND; + } else { + PT_RESTART(&s.pt); + } + } while(s.state != STATE_CONFIG_RECEIVED); + +#if 0 + printf("Got IP address %d.%d.%d.%d\n", + uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr), + uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr)); + printf("Got netmask %d.%d.%d.%d\n", + uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask), + uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask)); + printf("Got DNS server %d.%d.%d.%d\n", + uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr), + uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr)); + printf("Got default router %d.%d.%d.%d\n", + uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router), + uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router)); + printf("Lease expires in %ld seconds\n", + ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1])); +#endif + + dhcpc_configured(&s); + + /* timer_stop(&s.timer);*/ + + /* + * PT_END restarts the thread so we do this instead. Eventually we + * should reacquire expired leases here. + */ + while(1) { + PT_YIELD(&s.pt); + } + + PT_END(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_init(const void *mac_addr, int mac_len) +{ + uip_ipaddr_t addr; + + s.mac_addr = mac_addr; + s.mac_len = mac_len; + + s.state = STATE_INITIAL; + uip_ipaddr(addr, 255,255,255,255); + s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT)); + if(s.conn != NULL) { + uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT)); + } + PT_INIT(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_appcall(void) +{ + handle_dhcp(); +} +/*---------------------------------------------------------------------------*/ +void +dhcpc_request(void) +{ + u16_t ipaddr[2]; + + if(s.state == STATE_INITIAL) { + uip_ipaddr(ipaddr, 0,0,0,0); + uip_sethostaddr(ipaddr); + /* handle_dhcp(PROCESS_EVENT_NONE, NULL);*/ + } +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/dhcpc/dhcpc.h b/uip/apps/dhcpc/dhcpc.h new file mode 100644 index 0000000..c6550ec --- /dev/null +++ b/uip/apps/dhcpc/dhcpc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack + * + * @(#)$Id: dhcpc.h,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +#ifndef __DHCPC_H__ +#define __DHCPC_H__ + +#include "timer.h" +#include "pt.h" + +struct dhcpc_state { + struct pt pt; + char state; + struct uip_udp_conn *conn; + struct timer timer; + u16_t ticks; + const void *mac_addr; + int mac_len; + + u8_t serverid[4]; + + u16_t lease_time[2]; + u16_t ipaddr[2]; + u16_t netmask[2]; + u16_t dnsaddr[2]; + u16_t default_router[2]; +}; + +void dhcpc_init(const void *mac_addr, int mac_len); +void dhcpc_request(void); + +void dhcpc_appcall(void); + +void dhcpc_configured(const struct dhcpc_state *s); + +typedef struct dhcpc_state uip_udp_appstate_t; +#define UIP_UDP_APPCALL dhcpc_appcall + + +#endif /* __DHCPC_H__ */ diff --git a/uip/apps/hello-world/Makefile.hello-world b/uip/apps/hello-world/Makefile.hello-world new file mode 100644 index 0000000..e34aaf5 --- /dev/null +++ b/uip/apps/hello-world/Makefile.hello-world @@ -0,0 +1 @@ +APP_SOURCES += hello-world.c diff --git a/uip/apps/hello-world/hello-world.c b/uip/apps/hello-world/hello-world.c new file mode 100644 index 0000000..7d0697c --- /dev/null +++ b/uip/apps/hello-world/hello-world.c @@ -0,0 +1,100 @@ +/** + * \addtogroup helloworld + * @{ + */ + +/** + * \file + * An example of how to write uIP applications + * with protosockets. + * \author + * Adam Dunkels <adam@sics.se> + */ + +/* + * This is a short example of how to write uIP applications using + * protosockets. + */ + +/* + * We define the application state (struct hello_world_state) in the + * hello-world.h file, so we need to include it here. We also include + * uip.h (since this cannot be included in hello-world.h) and + * <string.h>, since we use the memcpy() function in the code. + */ +#include "hello-world.h" +#include "uip.h" +#include <string.h> + +/* + * Declaration of the protosocket function that handles the connection + * (defined at the end of the code). + */ +static int handle_connection(struct hello_world_state *s); +/*---------------------------------------------------------------------------*/ +/* + * The initialization function. We must explicitly call this function + * from the system initialization code, some time after uip_init() is + * called. + */ +void +hello_world_init(void) +{ + /* We start to listen for connections on TCP port 1000. */ + uip_listen(HTONS(1000)); +} +/*---------------------------------------------------------------------------*/ +/* + * In hello-world.h we have defined the UIP_APPCALL macro to + * hello_world_appcall so that this funcion is uIP's application + * function. This function is called whenever an uIP event occurs + * (e.g. when a new connection is established, new data arrives, sent + * data is acknowledged, data needs to be retransmitted, etc.). + */ +void +hello_world_appcall(void) +{ + /* + * The uip_conn structure has a field called "appstate" that holds + * the application state of the connection. We make a pointer to + * this to access it easier. + */ + struct hello_world_state *s = &(uip_conn->appstate); + + /* + * If a new connection was just established, we should initialize + * the protosocket in our applications' state structure. + */ + if(uip_connected()) { + PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer)); + } + + /* + * Finally, we run the protosocket function that actually handles + * the communication. We pass it a pointer to the application state + * of the current connection. + */ + handle_connection(s); +} +/*---------------------------------------------------------------------------*/ +/* + * This is the protosocket function that handles the communication. A + * protosocket function must always return an int, but must never + * explicitly return - all return statements are hidden in the PSOCK + * macros. + */ +static int +handle_connection(struct hello_world_state *s) +{ + PSOCK_BEGIN(&s->p); + + PSOCK_SEND_STR(&s->p, "Hello. What is your name?\n"); + PSOCK_READTO(&s->p, '\n'); + strncpy(s->name, s->inputbuffer, sizeof(s->name)); + PSOCK_SEND_STR(&s->p, "Hello "); + PSOCK_SEND_STR(&s->p, s->name); + PSOCK_CLOSE(&s->p); + + PSOCK_END(&s->p); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/hello-world/hello-world.h b/uip/apps/hello-world/hello-world.h new file mode 100644 index 0000000..5ef333b --- /dev/null +++ b/uip/apps/hello-world/hello-world.h @@ -0,0 +1,52 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup helloworld Hello, world + * @{ + * + * A small example showing how to write applications with + * \ref psock "protosockets". + */ + +/** + * \file + * Header file for an example of how to write uIP applications + * with protosockets. + * \author + * Adam Dunkels <adam@sics.se> + */ + +#ifndef __HELLO_WORLD_H__ +#define __HELLO_WORLD_H__ + +/* Since this file will be included by uip.h, we cannot include uip.h + here. But we might need to include uipopt.h if we need the u8_t and + u16_t datatypes. */ +#include "uipopt.h" + +#include "psock.h" + +/* Next, we define the uip_tcp_appstate_t datatype. This is the state + of our application, and the memory required for this state is + allocated together with each TCP connection. One application state + for each TCP connection. */ +typedef struct hello_world_state { + struct psock p; + char inputbuffer[10]; + char name[40]; +} uip_tcp_appstate_t; + +/* Finally we define the application function to be called by uIP. */ +void hello_world_appcall(void); +#ifndef UIP_APPCALL +#define UIP_APPCALL hello_world_appcall +#endif /* UIP_APPCALL */ + +void hello_world_init(void); + +#endif /* __HELLO_WORLD_H__ */ +/** @} */ +/** @} */ diff --git a/uip/apps/resolv/Makefile.resolv b/uip/apps/resolv/Makefile.resolv new file mode 100644 index 0000000..94c37d8 --- /dev/null +++ b/uip/apps/resolv/Makefile.resolv @@ -0,0 +1 @@ +APP_SOURCES += resolv.c diff --git a/uip/apps/resolv/resolv.c b/uip/apps/resolv/resolv.c new file mode 100644 index 0000000..30c8fb2 --- /dev/null +++ b/uip/apps/resolv/resolv.c @@ -0,0 +1,464 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup resolv DNS resolver + * @{ + * + * The uIP DNS resolver functions are used to lookup a hostname and + * map it to a numerical IP address. It maintains a list of resolved + * hostnames that can be queried with the resolv_lookup() + * function. New hostnames can be resolved using the resolv_query() + * function. + * + * When a hostname has been resolved (or found to be non-existant), + * the resolver code calls a callback function called resolv_found() + * that must be implemented by the module that uses the resolver. + */ + +/** + * \file + * DNS host name to IP address resolver. + * \author Adam Dunkels <adam@dunkels.com> + * + * This file implements a DNS host name to IP address resolver. + */ + +/* + * Copyright (c) 2002-2003, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: resolv.c,v 1.5 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "resolv.h" +#include "uip.h" + +#include <string.h> + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/** \internal The maximum number of retries when asking for a name. */ +#define MAX_RETRIES 8 + +/** \internal The DNS message header. */ +struct dns_hdr { + u16_t id; + u8_t flags1, flags2; +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + u16_t numquestions; + u16_t numanswers; + u16_t numauthrr; + u16_t numextrarr; +}; + +/** \internal The DNS answer message structure. */ +struct dns_answer { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + u16_t type; + u16_t class; + u16_t ttl[2]; + u16_t len; + uip_ipaddr_t ipaddr; +}; + +struct namemap { +#define STATE_UNUSED 0 +#define STATE_NEW 1 +#define STATE_ASKING 2 +#define STATE_DONE 3 +#define STATE_ERROR 4 + u8_t state; + u8_t tmr; + u8_t retries; + u8_t seqno; + u8_t err; + char name[32]; + uip_ipaddr_t ipaddr; +}; + +#ifndef UIP_CONF_RESOLV_ENTRIES +#define RESOLV_ENTRIES 4 +#else /* UIP_CONF_RESOLV_ENTRIES */ +#define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES +#endif /* UIP_CONF_RESOLV_ENTRIES */ + + +static struct namemap names[RESOLV_ENTRIES]; + +static u8_t seqno; + +static struct uip_udp_conn *resolv_conn = NULL; + + +/*---------------------------------------------------------------------------*/ +/** \internal + * Walk through a compact encoded DNS name and return the end of it. + * + * \return The end of the name. + */ +/*---------------------------------------------------------------------------*/ +static unsigned char * +parse_name(unsigned char *query) +{ + unsigned char n; + + do { + n = *query++; + + while(n > 0) { + /* printf("%c", *query);*/ + ++query; + --n; + }; + /* printf(".");*/ + } while(*query != 0); + /* printf("\n");*/ + return query + 1; +} +/*---------------------------------------------------------------------------*/ +/** \internal + * Runs through the list of names to see if there are any that have + * not yet been queried and, if so, sends out a query. + */ +/*---------------------------------------------------------------------------*/ +static void +check_entries(void) +{ + register struct dns_hdr *hdr; + char *query, *nptr, *nameptr; + static u8_t i; + static u8_t n; + register struct namemap *namemapptr; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + namemapptr = &names[i]; + if(namemapptr->state == STATE_NEW || + namemapptr->state == STATE_ASKING) { + if(namemapptr->state == STATE_ASKING) { + if(--namemapptr->tmr == 0) { + if(++namemapptr->retries == MAX_RETRIES) { + namemapptr->state = STATE_ERROR; + resolv_found(namemapptr->name, NULL); + continue; + } + namemapptr->tmr = namemapptr->retries; + } else { + /* printf("Timer %d\n", namemapptr->tmr);*/ + /* Its timer has not run out, so we move on to next + entry. */ + continue; + } + } else { + namemapptr->state = STATE_ASKING; + namemapptr->tmr = 1; + namemapptr->retries = 0; + } + hdr = (struct dns_hdr *)uip_appdata; + memset(hdr, 0, sizeof(struct dns_hdr)); + hdr->id = htons(i); + hdr->flags1 = DNS_FLAG1_RD; + hdr->numquestions = HTONS(1); + query = (char *)uip_appdata + 12; + nameptr = namemapptr->name; + --nameptr; + /* Convert hostname into suitable query format. */ + do { + ++nameptr; + nptr = query; + ++query; + for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) { + *query = *nameptr; + ++query; + ++n; + } + *nptr = n; + } while(*nameptr != 0); + { + static unsigned char endquery[] = + {0,0,1,0,1}; + memcpy(query, endquery, 5); + } + uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata)); + break; + } + } +} +/*---------------------------------------------------------------------------*/ +/** \internal + * Called when new UDP data arrives. + */ +/*---------------------------------------------------------------------------*/ +static void +newdata(void) +{ + char *nameptr; + struct dns_answer *ans; + struct dns_hdr *hdr; + static u8_t nquestions, nanswers; + static u8_t i; + register struct namemap *namemapptr; + + hdr = (struct dns_hdr *)uip_appdata; + /* printf("ID %d\n", htons(hdr->id)); + printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); + printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK); + printf("Num questions %d, answers %d, authrr %d, extrarr %d\n", + htons(hdr->numquestions), + htons(hdr->numanswers), + htons(hdr->numauthrr), + htons(hdr->numextrarr)); + */ + + /* The ID in the DNS header should be our entry into the name + table. */ + i = htons(hdr->id); + namemapptr = &names[i]; + if(i < RESOLV_ENTRIES && + namemapptr->state == STATE_ASKING) { + + /* This entry is now finished. */ + namemapptr->state = STATE_DONE; + namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; + + /* Check for error. If so, call callback to inform. */ + if(namemapptr->err != 0) { + namemapptr->state = STATE_ERROR; + resolv_found(namemapptr->name, NULL); + return; + } + + /* We only care about the question(s) and the answers. The authrr + and the extrarr are simply discarded. */ + nquestions = htons(hdr->numquestions); + nanswers = htons(hdr->numanswers); + + /* Skip the name in the question. XXX: This should really be + checked agains the name in the question, to be sure that they + match. */ + nameptr = parse_name((char *)uip_appdata + 12) + 4; + + while(nanswers > 0) { + /* The first byte in the answer resource record determines if it + is a compressed record or a normal one. */ + if(*nameptr & 0xc0) { + /* Compressed name. */ + nameptr +=2; + /* printf("Compressed anwser\n");*/ + } else { + /* Not compressed name. */ + nameptr = parse_name((char *)nameptr); + } + + ans = (struct dns_answer *)nameptr; + /* printf("Answer: type %x, class %x, ttl %x, length %x\n", + htons(ans->type), htons(ans->class), (htons(ans->ttl[0]) + << 16) | htons(ans->ttl[1]), htons(ans->len));*/ + + /* Check for IP address type and Internet class. Others are + discarded. */ + if(ans->type == HTONS(1) && + ans->class == HTONS(1) && + ans->len == HTONS(4)) { + /* printf("IP address %d.%d.%d.%d\n", + htons(ans->ipaddr[0]) >> 8, + htons(ans->ipaddr[0]) & 0xff, + htons(ans->ipaddr[1]) >> 8, + htons(ans->ipaddr[1]) & 0xff);*/ + /* XXX: we should really check that this IP address is the one + we want. */ + namemapptr->ipaddr[0] = ans->ipaddr[0]; + namemapptr->ipaddr[1] = ans->ipaddr[1]; + + resolv_found(namemapptr->name, namemapptr->ipaddr); + return; + } else { + nameptr = nameptr + 10 + htons(ans->len); + } + --nanswers; + } + } + +} +/*---------------------------------------------------------------------------*/ +/** \internal + * The main UDP function. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_appcall(void) +{ + if(uip_udp_conn->rport == HTONS(53)) { + if(uip_poll()) { + check_entries(); + } + if(uip_newdata()) { + newdata(); + } + } +} +/*---------------------------------------------------------------------------*/ +/** + * Queues a name so that a question for the name will be sent out. + * + * \param name The hostname that is to be queried. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_query(char *name) +{ + static u8_t i; + static u8_t lseq, lseqi; + register struct namemap *nameptr; + + lseq = lseqi = 0; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + nameptr = &names[i]; + if(nameptr->state == STATE_UNUSED) { + break; + } + if(seqno - nameptr->seqno > lseq) { + lseq = seqno - nameptr->seqno; + lseqi = i; + } + } + + if(i == RESOLV_ENTRIES) { + i = lseqi; + nameptr = &names[i]; + } + + /* printf("Using entry %d\n", i);*/ + + strcpy(nameptr->name, name); + nameptr->state = STATE_NEW; + nameptr->seqno = seqno; + ++seqno; +} +/*---------------------------------------------------------------------------*/ +/** + * Look up a hostname in the array of known hostnames. + * + * \note This function only looks in the internal array of known + * hostnames, it does not send out a query for the hostname if none + * was found. The function resolv_query() can be used to send a query + * for a hostname. + * + * \return A pointer to a 4-byte representation of the hostname's IP + * address, or NULL if the hostname was not found in the array of + * hostnames. + */ +/*---------------------------------------------------------------------------*/ +u16_t * +resolv_lookup(char *name) +{ + static u8_t i; + struct namemap *nameptr; + + /* Walk through the list to see if the name is in there. If it is + not, we return NULL. */ + for(i = 0; i < RESOLV_ENTRIES; ++i) { + nameptr = &names[i]; + if(nameptr->state == STATE_DONE && + strcmp(name, nameptr->name) == 0) { + return nameptr->ipaddr; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +/** + * Obtain the currently configured DNS server. + * + * \return A pointer to a 4-byte representation of the IP address of + * the currently configured DNS server or NULL if no DNS server has + * been configured. + */ +/*---------------------------------------------------------------------------*/ +u16_t * +resolv_getserver(void) +{ + if(resolv_conn == NULL) { + return NULL; + } + return resolv_conn->ripaddr; +} +/*---------------------------------------------------------------------------*/ +/** + * Configure which DNS server to use for queries. + * + * \param dnsserver A pointer to a 4-byte representation of the IP + * address of the DNS server to be configured. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_conf(u16_t *dnsserver) +{ + if(resolv_conn != NULL) { + uip_udp_remove(resolv_conn); + } + + resolv_conn = uip_udp_new((uip_ipaddr_t *)dnsserver, HTONS(53)); +} +/*---------------------------------------------------------------------------*/ +/** + * Initalize the resolver. + */ +/*---------------------------------------------------------------------------*/ +void +resolv_init(void) +{ + static u8_t i; + + for(i = 0; i < RESOLV_ENTRIES; ++i) { + names[i].state = STATE_DONE; + } + +} +/*---------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/uip/apps/resolv/resolv.h b/uip/apps/resolv/resolv.h new file mode 100644 index 0000000..abab34e --- /dev/null +++ b/uip/apps/resolv/resolv.h @@ -0,0 +1,75 @@ +/** + * \addtogroup resolv + * @{ + */ +/** + * \file + * DNS resolver code header file. + * \author Adam Dunkels <adam@dunkels.com> + */ + +/* + * Copyright (c) 2002-2003, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: resolv.h,v 1.4 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __RESOLV_H__ +#define __RESOLV_H__ + +typedef int uip_udp_appstate_t; +void resolv_appcall(void); +#define UIP_UDP_APPCALL resolv_appcall + +#include "uipopt.h" + +/** + * Callback function which is called when a hostname is found. + * + * This function must be implemented by the module that uses the DNS + * resolver. It is called when a hostname is found, or when a hostname + * was not found. + * + * \param name A pointer to the name that was looked up. \param + * ipaddr A pointer to a 4-byte array containing the IP address of the + * hostname, or NULL if the hostname could not be found. + */ +void resolv_found(char *name, u16_t *ipaddr); + +/* Functions. */ +void resolv_conf(u16_t *dnsserver); +u16_t *resolv_getserver(void); +void resolv_init(void); +u16_t *resolv_lookup(char *name); +void resolv_query(char *name); + +#endif /* __RESOLV_H__ */ + +/** @} */ diff --git a/uip/apps/smtp/Makefile.smtp b/uip/apps/smtp/Makefile.smtp new file mode 100644 index 0000000..8b3a5aa --- /dev/null +++ b/uip/apps/smtp/Makefile.smtp @@ -0,0 +1 @@ +APP_SOURCES += smtp.c smtp-strings.c memb.c diff --git a/uip/apps/smtp/makestrings b/uip/apps/smtp/makestrings new file mode 100755 index 0000000..bea18a6 --- /dev/null +++ b/uip/apps/smtp/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while(<FILE>) { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "};\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("smtp-strings"); + +exit 0; + diff --git a/uip/apps/smtp/smtp-strings b/uip/apps/smtp/smtp-strings new file mode 100644 index 0000000..27f639c --- /dev/null +++ b/uip/apps/smtp/smtp-strings @@ -0,0 +1,11 @@ +smtp_220 "220" +smtp_helo "HELO " +smtp_mail_from "MAIL FROM: " +smtp_rcpt_to "RCPT TO: " +smtp_data "DATA\r\n" +smtp_to "To: " +smtp_from "From: " +smtp_subject "Subject: " +smtp_quit "QUIT\r\n" +smtp_crnl "\r\n" +smtp_crnlperiodcrnl "\r\n.\r\n"
\ No newline at end of file diff --git a/uip/apps/smtp/smtp-strings.c b/uip/apps/smtp/smtp-strings.c new file mode 100644 index 0000000..f3981a1 --- /dev/null +++ b/uip/apps/smtp/smtp-strings.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: smtp-strings.c,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +const char smtp_220[4] = +/* "220" */ +{0x32, 0x32, 0x30, }; +const char smtp_helo[6] = +/* "HELO " */ +{0x48, 0x45, 0x4c, 0x4f, 0x20, }; +const char smtp_mail_from[12] = +/* "MAIL FROM: " */ +{0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x20, }; +const char smtp_rcpt_to[10] = +/* "RCPT TO: " */ +{0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x20, }; +const char smtp_data[7] = +/* "DATA\r\n" */ +{0x44, 0x41, 0x54, 0x41, 0xd, 0xa, }; +const char smtp_to[5] = +/* "To: " */ +{0x54, 0x6f, 0x3a, 0x20, }; +const char smtp_cc[5] = +/* "Cc: " */ +{0x43, 0x63, 0x3a, 0x20, }; +const char smtp_from[7] = +/* "From: " */ +{0x46, 0x72, 0x6f, 0x6d, 0x3a, 0x20, }; +const char smtp_subject[10] = +/* "Subject: " */ +{0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x20, }; +const char smtp_quit[7] = +/* "QUIT\r\n" */ +{0x51, 0x55, 0x49, 0x54, 0xd, 0xa, }; +const char smtp_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, }; +const char smtp_crnlperiodcrnl[6] = +/* "\r\n.\r\n" */ +{0xd, 0xa, 0x2e, 0xd, 0xa, }; diff --git a/uip/apps/smtp/smtp-strings.h b/uip/apps/smtp/smtp-strings.h new file mode 100644 index 0000000..f5ae68c --- /dev/null +++ b/uip/apps/smtp/smtp-strings.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: smtp-strings.h,v 1.3 2006/06/11 21:46:37 adam Exp $ + */ +extern const char smtp_220[4]; +extern const char smtp_helo[6]; +extern const char smtp_mail_from[12]; +extern const char smtp_rcpt_to[10]; +extern const char smtp_data[7]; +extern const char smtp_to[5]; +extern const char smtp_cc[5]; +extern const char smtp_from[7]; +extern const char smtp_subject[10]; +extern const char smtp_quit[7]; +extern const char smtp_crnl[3]; +extern const char smtp_crnlperiodcrnl[6]; diff --git a/uip/apps/smtp/smtp.c b/uip/apps/smtp/smtp.c new file mode 100644 index 0000000..a860006 --- /dev/null +++ b/uip/apps/smtp/smtp.c @@ -0,0 +1,262 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup smtp SMTP E-mail sender + * @{ + * + * The Simple Mail Transfer Protocol (SMTP) as defined by RFC821 is + * the standard way of sending and transfering e-mail on the + * Internet. This simple example implementation is intended as an + * example of how to implement protocols in uIP, and is able to send + * out e-mail but has not been extensively tested. + */ + +/** + * \file + * SMTP example implementation + * \author Adam Dunkels <adam@dunkels.com> + */ + +/* + * Copyright (c) 2004, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: smtp.c,v 1.4 2006/06/11 21:46:37 adam Exp $ + */ +#include "smtp.h" + +#include "smtp-strings.h" +#include "psock.h" +#include "uip.h" + +#include <string.h> + +static struct smtp_state s; + +static char *localhostname; +static uip_ipaddr_t smtpserver; + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +#define ISO_period 0x2e + +#define ISO_2 0x32 +#define ISO_3 0x33 +#define ISO_4 0x34 +#define ISO_5 0x35 + + +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(smtp_thread(void)) +{ + PSOCK_BEGIN(&s.psock); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(strncmp(s.inputbuffer, smtp_220, 3) != 0) { + PSOCK_CLOSE(&s.psock); + smtp_done(2); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_helo); + PSOCK_SEND_STR(&s.psock, localhostname); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(3); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_mail_from); + PSOCK_SEND_STR(&s.psock, s.from); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(4); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_rcpt_to); + PSOCK_SEND_STR(&s.psock, s.to); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(5); + PSOCK_EXIT(&s.psock); + } + + if(s.cc != 0) { + PSOCK_SEND_STR(&s.psock, (char *)smtp_rcpt_to); + PSOCK_SEND_STR(&s.psock, s.cc); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(6); + PSOCK_EXIT(&s.psock); + } + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_data); + + PSOCK_READTO(&s.psock, ISO_nl); + + if(s.inputbuffer[0] != ISO_3) { + PSOCK_CLOSE(&s.psock); + smtp_done(7); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_to); + PSOCK_SEND_STR(&s.psock, s.to); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + if(s.cc != 0) { + PSOCK_SEND_STR(&s.psock, (char *)smtp_cc); + PSOCK_SEND_STR(&s.psock, s.cc); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_from); + PSOCK_SEND_STR(&s.psock, s.from); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_SEND_STR(&s.psock, (char *)smtp_subject); + PSOCK_SEND_STR(&s.psock, s.subject); + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnl); + + PSOCK_SEND(&s.psock, s.msg, s.msglen); + + PSOCK_SEND_STR(&s.psock, (char *)smtp_crnlperiodcrnl); + + PSOCK_READTO(&s.psock, ISO_nl); + if(s.inputbuffer[0] != ISO_2) { + PSOCK_CLOSE(&s.psock); + smtp_done(8); + PSOCK_EXIT(&s.psock); + } + + PSOCK_SEND_STR(&s.psock, (char *)smtp_quit); + smtp_done(SMTP_ERR_OK); + PSOCK_END(&s.psock); +} +/*---------------------------------------------------------------------------*/ +void +smtp_appcall(void) +{ + if(uip_closed()) { + s.connected = 0; + return; + } + if(uip_aborted() || uip_timedout()) { + s.connected = 0; + smtp_done(1); + return; + } + smtp_thread(); +} +/*---------------------------------------------------------------------------*/ +/** + * Specificy an SMTP server and hostname. + * + * This function is used to configure the SMTP module with an SMTP + * server and the hostname of the host. + * + * \param lhostname The hostname of the uIP host. + * + * \param server A pointer to a 4-byte array representing the IP + * address of the SMTP server to be configured. + */ +void +smtp_configure(char *lhostname, void *server) +{ + localhostname = lhostname; + uip_ipaddr_copy(smtpserver, server); +} +/*---------------------------------------------------------------------------*/ +/** + * Send an e-mail. + * + * \param to The e-mail address of the receiver of the e-mail. + * \param cc The e-mail address of the CC: receivers of the e-mail. + * \param from The e-mail address of the sender of the e-mail. + * \param subject The subject of the e-mail. + * \param msg The actual e-mail message. + * \param msglen The length of the e-mail message. + */ +unsigned char +smtp_send(char *to, char *cc, char *from, + char *subject, char *msg, u16_t msglen) +{ + struct uip_conn *conn; + + conn = uip_connect(smtpserver, HTONS(25)); + if(conn == NULL) { + return 0; + } + s.connected = 1; + s.to = to; + s.cc = cc; + s.from = from; + s.subject = subject; + s.msg = msg; + s.msglen = msglen; + + PSOCK_INIT(&s.psock, s.inputbuffer, sizeof(s.inputbuffer)); + + return 1; +} +/*---------------------------------------------------------------------------*/ +void +smtp_init(void) +{ + s.connected = 0; +} +/*---------------------------------------------------------------------------*/ +/** @} */ +/** @} */ diff --git a/uip/apps/smtp/smtp.h b/uip/apps/smtp/smtp.h new file mode 100644 index 0000000..44d0766 --- /dev/null +++ b/uip/apps/smtp/smtp.h @@ -0,0 +1,103 @@ + +/** + * \addtogroup smtp + * @{ + */ + + +/** + * \file + * SMTP header file + * \author Adam Dunkels <adam@dunkels.com> + */ + +/* + * Copyright (c) 2002, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: smtp.h,v 1.4 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __SMTP_H__ +#define __SMTP_H__ + +#include "uipopt.h" + +/** + * Error number that signifies a non-error condition. + */ +#define SMTP_ERR_OK 0 + +/** + * Callback function that is called when an e-mail transmission is + * done. + * + * This function must be implemented by the module that uses the SMTP + * module. + * + * \param error The number of the error if an error occured, or + * SMTP_ERR_OK. + */ +void smtp_done(unsigned char error); + +void smtp_init(void); + +/* Functions. */ +void smtp_configure(char *localhostname, u16_t *smtpserver); +unsigned char smtp_send(char *to, char *from, + char *subject, char *msg, + u16_t msglen); +#define SMTP_SEND(to, cc, from, subject, msg) \ + smtp_send(to, cc, from, subject, msg, strlen(msg)) + +void smtp_appcall(void); + +struct smtp_state { + u8_t state; + char *to; + char *from; + char *subject; + char *msg; + u16_t msglen; + + u16_t sentlen, textlen; + u16_t sendptr; + +}; + + +#ifndef UIP_APPCALL +#define UIP_APPCALL smtp_appcall +#endif +typedef struct smtp_state uip_tcp_appstate_t; + + +#endif /* __SMTP_H__ */ + +/** @} */ diff --git a/uip/apps/telnet/Makefile.telnet b/uip/apps/telnet/Makefile.telnet new file mode 100644 index 0000000..8b94786 --- /dev/null +++ b/uip/apps/telnet/Makefile.telnet @@ -0,0 +1 @@ +APP_SOURCES += telnet.c diff --git a/uip/apps/telnet/telnet.c b/uip/apps/telnet/telnet.c new file mode 100644 index 0000000..f72b6fc --- /dev/null +++ b/uip/apps/telnet/telnet.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2002, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: telnet.c,v 1.1.2.3 2003/10/06 11:20:45 adam Exp $ + * + */ + +#include "uip.h" + +#include "telnet.h" + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +#define FLAG_CLOSE 1 +#define FLAG_ABORT 2 +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_send(struct telnet_state *s, char *text, u16_t len) +{ + if(s->text != NULL) { + return 1; + } + s->text = text; + s->textlen = len; + s->sentlen = 0; + return 0; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_close(struct telnet_state *s) +{ + s->flags = FLAG_CLOSE; + if(s->text != NULL) { + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +telnet_abort(struct telnet_state *s) +{ + s->flags = FLAG_ABORT; + if(s->text != NULL) { + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +static void +acked(struct telnet_state *s) +{ + s->textlen -= s->sentlen; + if(s->textlen == 0) { + s->text = NULL; + telnet_sent(s); + } else { + s->text += s->sentlen; + } + s->sentlen = 0; +} +/*-----------------------------------------------------------------------------------*/ +static void +senddata(struct telnet_state *s) +{ + if(s->text == NULL) { + uip_send(s->text, 0); + return; + } + if(s->textlen > uip_mss()) { + s->sentlen = uip_mss(); + } else { + s->sentlen = s->textlen; + } + uip_send(s->text, s->sentlen); +} +/*-----------------------------------------------------------------------------------*/ +void telnet_app(void) +{ + struct telnet_state *s = (struct telnet_state *)uip_conn->appstate; + + if(uip_connected()) { + s->flags = 0; + telnet_connected(s); + senddata(s); + return; + } + + if(uip_closed()) { + telnet_closed(s); + } + + if(uip_aborted()) { + telnet_aborted(s); + } + if(uip_timedout()) { + telnet_timedout(s); + } + + + if(s->flags & FLAG_CLOSE) { + uip_close(); + return; + } + if(s->flags & FLAG_ABORT) { + uip_abort(); + return; + } + if(uip_acked()) { + acked(s); + } + if(uip_newdata()) { + telnet_newdata(s, (char *)uip_appdata, uip_datalen()); + } + if(uip_rexmit() || + uip_newdata() || + uip_acked()) { + senddata(s); + } else if(uip_poll()) { + senddata(s); + } +} +/*-----------------------------------------------------------------------------------*/ diff --git a/uip/apps/telnet/telnet.h b/uip/apps/telnet/telnet.h new file mode 100644 index 0000000..a48c8ee --- /dev/null +++ b/uip/apps/telnet/telnet.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2002, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: telnet.h,v 1.1.2.4 2003/10/06 22:56:45 adam Exp $ + * + */ +#ifndef __TELNET_H__ +#define __TELNET_H__ + +struct telnet_state { + unsigned char flags; + char *text; + u16_t textlen; + u16_t sentlen; +}; + +typedef struct telnet_state uip_tcp_appstate_t; +void telnet_app(void); + +#ifndef UIP_APPCALL +#define UIP_APPCALL telnet_app +#endif + +#ifndef UIP_APPSTATE_SIZE +#define UIP_APPSTATE_SIZE (sizeof(struct telnet_state)) +#endif + + +unsigned char telnet_send(struct telnet_state *s, char *text, u16_t len); +unsigned char telnet_close(struct telnet_state *s); +unsigned char telnet_abort(struct telnet_state *s); + +/* Callbacks, must be implemented by the caller. */ +void telnet_connected(struct telnet_state *s); +void telnet_closed(struct telnet_state *s); +void telnet_sent(struct telnet_state *s); +void telnet_aborted(struct telnet_state *s); +void telnet_timedout(struct telnet_state *s); +void telnet_newdata(struct telnet_state *s, char *data, u16_t len); +#endif /* __TELNET_H__ */ diff --git a/uip/apps/telnetd/Makefile.telnetd b/uip/apps/telnetd/Makefile.telnetd new file mode 100644 index 0000000..afb1b59 --- /dev/null +++ b/uip/apps/telnetd/Makefile.telnetd @@ -0,0 +1 @@ +APP_SOURCES += telnetd.c shell.c memb.c diff --git a/uip/apps/telnetd/shell.c b/uip/apps/telnetd/shell.c new file mode 100644 index 0000000..9345cae --- /dev/null +++ b/uip/apps/telnetd/shell.c @@ -0,0 +1,123 @@ + /* + * Copyright (c) 2003, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: shell.c,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ + +#include "shell.h" + +#include <string.h> + +struct ptentry { + char *commandstr; + void (* pfunc)(char *str); +}; + +#define SHELL_PROMPT "uIP 1.0> " + +/*---------------------------------------------------------------------------*/ +static void +parse(register char *str, struct ptentry *t) +{ + struct ptentry *p; + for(p = t; p->commandstr != NULL; ++p) { + if(strncmp(p->commandstr, str, strlen(p->commandstr)) == 0) { + break; + } + } + + p->pfunc(str); +} +/*---------------------------------------------------------------------------*/ +static void +inttostr(register char *str, unsigned int i) +{ + str[0] = '0' + i / 100; + if(str[0] == '0') { + str[0] = ' '; + } + str[1] = '0' + (i / 10) % 10; + if(str[0] == ' ' && str[1] == '0') { + str[1] = ' '; + } + str[2] = '0' + i % 10; + str[3] = ' '; + str[4] = 0; +} +/*---------------------------------------------------------------------------*/ +static void +help(char *str) +{ + shell_output("Available commands:", ""); + shell_output("stats - show network statistics", ""); + shell_output("conn - show TCP connections", ""); + shell_output("help, ? - show help", ""); + shell_output("exit - exit shell", ""); +} +/*---------------------------------------------------------------------------*/ +static void +unknown(char *str) +{ + if(strlen(str) > 0) { + shell_output("Unknown command: ", str); + } +} +/*---------------------------------------------------------------------------*/ +static struct ptentry parsetab[] = + {{"stats", help}, + {"conn", help}, + {"help", help}, + {"exit", shell_quit}, + {"?", help}, + + /* Default action */ + {NULL, unknown}}; +/*---------------------------------------------------------------------------*/ +void +shell_init(void) +{ +} +/*---------------------------------------------------------------------------*/ +void +shell_start(void) +{ + shell_output("uIP command shell", ""); + shell_output("Type '?' and return for help", ""); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ +void +shell_input(char *cmd) +{ + parse(cmd, parsetab); + shell_prompt(SHELL_PROMPT); +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/telnetd/shell.h b/uip/apps/telnetd/shell.h new file mode 100644 index 0000000..b57d7be --- /dev/null +++ b/uip/apps/telnetd/shell.h @@ -0,0 +1,104 @@ +/** + * \file + * Interface for the Contiki shell. + * \author Adam Dunkels <adam@dunkels.com> + * + * Some of the functions declared in this file must be implemented as + * a shell back-end in the architecture specific files of a Contiki + * port. + */ + + +/* + * Copyright (c) 2003, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the Contiki desktop OS. + * + * $Id: shell.h,v 1.1 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +/** + * Initialize the shell. + * + * Called when the shell front-end process starts. This function may + * be used to start listening for signals. + */ +void shell_init(void); + +/** + * Start the shell back-end. + * + * Called by the front-end when a new shell is started. + */ +void shell_start(void); + +/** + * Process a shell command. + * + * This function will be called by the shell GUI / telnet server whan + * a command has been entered that should be processed by the shell + * back-end. + * + * \param command The command to be processed. + */ +void shell_input(char *command); + +/** + * Quit the shell. + * + */ +void shell_quit(char *); + + +/** + * Print a string to the shell window. + * + * This function is implemented by the shell GUI / telnet server and + * can be called by the shell back-end to output a string in the + * shell window. The string is automatically appended with a linebreak. + * + * \param str1 The first half of the string to be output. + * \param str2 The second half of the string to be output. + */ +void shell_output(char *str1, char *str2); + +/** + * Print a prompt to the shell window. + * + * This function can be used by the shell back-end to print out a + * prompt to the shell window. + * + * \param prompt The prompt to be printed. + * + */ +void shell_prompt(char *prompt); + +#endif /* __SHELL_H__ */ diff --git a/uip/apps/telnetd/telnetd.c b/uip/apps/telnetd/telnetd.c new file mode 100644 index 0000000..7a5ae85 --- /dev/null +++ b/uip/apps/telnetd/telnetd.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2003, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ + +#include "uip.h" +#include "telnetd.h" +#include "memb.h" +#include "shell.h" + +#include <string.h> + +#define ISO_nl 0x0a +#define ISO_cr 0x0d + +struct telnetd_line { + char line[TELNETD_CONF_LINELEN]; +}; +MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); + +#define STATE_NORMAL 0 +#define STATE_IAC 1 +#define STATE_WILL 2 +#define STATE_WONT 3 +#define STATE_DO 4 +#define STATE_DONT 5 +#define STATE_CLOSE 6 + +static struct telnetd_state s; + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 +/*---------------------------------------------------------------------------*/ +static char * +alloc_line(void) +{ + return memb_alloc(&linemem); +} +/*---------------------------------------------------------------------------*/ +static void +dealloc_line(char *line) +{ + memb_free(&linemem, line); +} +/*---------------------------------------------------------------------------*/ +void +shell_quit(char *str) +{ + s.state = STATE_CLOSE; +} +/*---------------------------------------------------------------------------*/ +static void +sendline(char *line) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] == NULL) { + s.lines[i] = line; + break; + } + } + if(i == TELNETD_CONF_NUMLINES) { + dealloc_line(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_prompt(char *str) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + strncpy(line, str, TELNETD_CONF_LINELEN); + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +shell_output(char *str1, char *str2) +{ + static unsigned len; + char *line; + + line = alloc_line(); + if(line != NULL) { + len = strlen(str1); + strncpy(line, str1, TELNETD_CONF_LINELEN); + if(len < TELNETD_CONF_LINELEN) { + strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); + } + len = strlen(line); + if(len < TELNETD_CONF_LINELEN - 2) { + line[len] = ISO_cr; + line[len+1] = ISO_nl; + line[len+2] = 0; + } + /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +void +telnetd_init(void) +{ + uip_listen(HTONS(23)); + memb_init(&linemem); + shell_init(); +} +/*---------------------------------------------------------------------------*/ +static void +acked(void) +{ + static unsigned int i; + + while(s.numsent > 0) { + dealloc_line(s.lines[0]); + for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i - 1] = s.lines[i]; + } + s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; + --s.numsent; + } +} +/*---------------------------------------------------------------------------*/ +static void +senddata(void) +{ + static char *bufptr, *lineptr; + static int buflen, linelen; + + bufptr = uip_appdata; + buflen = 0; + for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && + s.lines[s.numsent] != NULL ; ++s.numsent) { + lineptr = s.lines[s.numsent]; + linelen = strlen(lineptr); + if(linelen > TELNETD_CONF_LINELEN) { + linelen = TELNETD_CONF_LINELEN; + } + if(buflen + linelen < uip_mss()) { + memcpy(bufptr, lineptr, linelen); + bufptr += linelen; + buflen += linelen; + } else { + break; + } + } + uip_send(uip_appdata, buflen); +} +/*---------------------------------------------------------------------------*/ +static void +closed(void) +{ + static unsigned int i; + + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + if(s.lines[i] != NULL) { + dealloc_line(s.lines[i]); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +get_char(u8_t c) +{ + if(c == ISO_cr) { + return; + } + + s.buf[(int)s.bufptr] = c; + if(s.buf[(int)s.bufptr] == ISO_nl || + s.bufptr == sizeof(s.buf) - 1) { + if(s.bufptr > 0) { + s.buf[(int)s.bufptr] = 0; + /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ + } + shell_input(s.buf); + s.bufptr = 0; + } else { + ++s.bufptr; + } +} +/*---------------------------------------------------------------------------*/ +static void +sendopt(u8_t option, u8_t value) +{ + char *line; + line = alloc_line(); + if(line != NULL) { + line[0] = TELNET_IAC; + line[1] = option; + line[2] = value; + line[3] = 0; + sendline(line); + } +} +/*---------------------------------------------------------------------------*/ +static void +newdata(void) +{ + u16_t len; + u8_t c; + char *dataptr; + + + len = uip_datalen(); + dataptr = (char *)uip_appdata; + + while(len > 0 && s.bufptr < sizeof(s.buf)) { + c = *dataptr; + ++dataptr; + --len; + switch(s.state) { + case STATE_IAC: + if(c == TELNET_IAC) { + get_char(c); + s.state = STATE_NORMAL; + } else { + switch(c) { + case TELNET_WILL: + s.state = STATE_WILL; + break; + case TELNET_WONT: + s.state = STATE_WONT; + break; + case TELNET_DO: + s.state = STATE_DO; + break; + case TELNET_DONT: + s.state = STATE_DONT; + break; + default: + s.state = STATE_NORMAL; + break; + } + } + break; + case STATE_WILL: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + + case STATE_WONT: + /* Reply with a DONT */ + sendopt(TELNET_DONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DO: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_DONT: + /* Reply with a WONT */ + sendopt(TELNET_WONT, c); + s.state = STATE_NORMAL; + break; + case STATE_NORMAL: + if(c == TELNET_IAC) { + s.state = STATE_IAC; + } else { + get_char(c); + } + break; + } + + + } + +} +/*---------------------------------------------------------------------------*/ +void +telnetd_appcall(void) +{ + static unsigned int i; + if(uip_connected()) { + /* tcp_markconn(uip_conn, &s);*/ + for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { + s.lines[i] = NULL; + } + s.bufptr = 0; + s.state = STATE_NORMAL; + + shell_start(); + } + + if(s.state == STATE_CLOSE) { + s.state = STATE_NORMAL; + uip_close(); + return; + } + + if(uip_closed() || + uip_aborted() || + uip_timedout()) { + closed(); + } + + if(uip_acked()) { + acked(); + } + + if(uip_newdata()) { + newdata(); + } + + if(uip_rexmit() || + uip_newdata() || + uip_acked() || + uip_connected() || + uip_poll()) { + senddata(); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/uip/apps/telnetd/telnetd.h b/uip/apps/telnetd/telnetd.h new file mode 100644 index 0000000..2ee8acd --- /dev/null +++ b/uip/apps/telnetd/telnetd.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, 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 notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: telnetd.h,v 1.2 2006/06/07 09:43:54 adam Exp $ + * + */ +#ifndef __TELNETD_H__ +#define __TELNETD_H__ + +#include "uipopt.h" + +void telnetd_appcall(void); + +#ifndef TELNETD_CONF_LINELEN +#define TELNETD_CONF_LINELEN 40 +#endif +#ifndef TELNETD_CONF_NUMLINES +#define TELNETD_CONF_NUMLINES 16 +#endif + +struct telnetd_state { + char *lines[TELNETD_CONF_NUMLINES]; + char buf[TELNETD_CONF_LINELEN]; + char bufptr; + u8_t numsent; + u8_t state; +}; + +typedef struct telnetd_state uip_tcp_appstate_t; + +#ifndef UIP_APPCALL +#define UIP_APPCALL telnetd_appcall +#endif + +#endif /* __TELNETD_H__ */ diff --git a/uip/apps/webclient/Makefile.webclient b/uip/apps/webclient/Makefile.webclient new file mode 100644 index 0000000..e6e7f08 --- /dev/null +++ b/uip/apps/webclient/Makefile.webclient @@ -0,0 +1 @@ +APP_SOURCES += webclient-strings.c webclient.c diff --git a/uip/apps/webclient/makestrings b/uip/apps/webclient/makestrings new file mode 100755 index 0000000..6dec075 --- /dev/null +++ b/uip/apps/webclient/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while(<FILE>) { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "0 };\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("webclient-strings"); + +exit 0; + diff --git a/uip/apps/webclient/webclient-strings b/uip/apps/webclient/webclient-strings new file mode 100644 index 0000000..a331397 --- /dev/null +++ b/uip/apps/webclient/webclient-strings @@ -0,0 +1,31 @@ +http_http "http://" +http_200 "200 " +http_301 "301 " +http_302 "302 " +http_get "GET " +http_10 "HTTP/1.0" +http_11 "HTTP/1.1" +http_content_type "content-type: " +http_texthtml "text/html" +http_location "location: " +http_host "host: " +http_crnl "\r\n" +http_index_html "/index.html" +http_404_html "/404.html" +http_content_type_html "Content-type: text/html\r\n\r\n" +http_content_type_css "Content-type: text/css\r\n\r\n" +http_content_type_text "Content-type: text/text\r\n\r\n" +http_content_type_png "Content-type: image/png\r\n\r\n" +http_content_type_gif "Content-type: image/gif\r\n\r\n" +http_content_type_jpg "Content-type: image/jpeg\r\n\r\n" +http_content_type_binary "Content-type: application/octet-stream\r\n\r\n" +http_html ".html" +http_shtml ".shtml" +http_htm ".htm" +http_css ".css" +http_png ".png" +http_gif ".gif" +http_jpg ".jpg" +http_text ".text" +http_txt ".txt" +http_user_agent_fields "Connection: close\r\nUser-Agent: uIP/1.0 (; http://www.sics.se/~adam/uip/)\r\n\r\n" diff --git a/uip/apps/webclient/webclient-strings.c b/uip/apps/webclient/webclient-strings.c new file mode 100644 index 0000000..9472330 --- /dev/null +++ b/uip/apps/webclient/webclient-strings.c @@ -0,0 +1,93 @@ +const char http_http[8] = +/* "http://" */ +{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0 }; +const char http_200[5] = +/* "200 " */ +{0x32, 0x30, 0x30, 0x20, 0 }; +const char http_301[5] = +/* "301 " */ +{0x33, 0x30, 0x31, 0x20, 0 }; +const char http_302[5] = +/* "302 " */ +{0x33, 0x30, 0x32, 0x20, 0 }; +const char http_get[5] = +/* "GET " */ +{0x47, 0x45, 0x54, 0x20, 0 }; +const char http_10[9] = +/* "HTTP/1.0" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0 }; +const char http_11[9] = +/* "HTTP/1.1" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0 }; +const char http_content_type[15] = +/* "content-type: " */ +{0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0 }; +const char http_texthtml[10] = +/* "text/html" */ +{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_location[11] = +/* "location: " */ +{0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0 }; +const char http_host[7] = +/* "host: " */ +{0x68, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0 }; +const char http_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, 0 }; +const char http_index_html[12] = +/* "/index.html" */ +{0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_404_html[10] = +/* "/404.html" */ +{0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_content_type_html[28] = +/* "Content-type: text/html\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_css [27] = +/* "Content-type: text/css\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_text[28] = +/* "Content-type: text/text\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x65, 0x78, 0x74, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_png [28] = +/* "Content-type: image/png\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_gif [28] = +/* "Content-type: image/gif\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_jpg [29] = +/* "Content-type: image/jpeg\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_content_type_binary[43] = +/* "Content-type: application/octet-stream\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0xd, 0xa, 0xd, 0xa, 0 }; +const char http_html[6] = +/* ".html" */ +{0x2e, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_shtml[7] = +/* ".shtml" */ +{0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0 }; +const char http_htm[5] = +/* ".htm" */ +{0x2e, 0x68, 0x74, 0x6d, 0 }; +const char http_css[5] = +/* ".css" */ +{0x2e, 0x63, 0x73, 0x73, 0 }; +const char http_png[5] = +/* ".png" */ +{0x2e, 0x70, 0x6e, 0x67, 0 }; +const char http_gif[5] = +/* ".gif" */ +{0x2e, 0x67, 0x69, 0x66, 0 }; +const char http_jpg[5] = +/* ".jpg" */ +{0x2e, 0x6a, 0x70, 0x67, 0 }; +const char http_text[6] = +/* ".text" */ +{0x2e, 0x74, 0x65, 0x78, 0x74, 0 }; +const char http_txt[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, 0 }; +const char http_user_agent_fields[77] = +/* "Connection: close\r\nUser-Agent: uIP/1.0 (; http://www.sics.se/~adam/uip/)\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x28, 0x3b, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x29, 0xd, 0xa, 0xd, 0xa, 0 }; diff --git a/uip/apps/webclient/webclient-strings.h b/uip/apps/webclient/webclient-strings.h new file mode 100644 index 0000000..9e3ec93 --- /dev/null +++ b/uip/apps/webclient/webclient-strings.h @@ -0,0 +1,31 @@ +extern const char http_http[8]; +extern const char http_200[5]; +extern const char http_301[5]; +extern const char http_302[5]; +extern const char http_get[5]; +extern const char http_10[9]; +extern const char http_11[9]; +extern const char http_content_type[15]; +extern const char http_texthtml[10]; +extern const char http_location[11]; +extern const char http_host[7]; +extern const char http_crnl[3]; +extern const char http_index_html[12]; +extern const char http_404_html[10]; +extern const char http_content_type_html[28]; +extern const char http_content_type_css [27]; +extern const char http_content_type_text[28]; +extern const char http_content_type_png [28]; +extern const char http_content_type_gif [28]; +extern const char http_content_type_jpg [29]; +extern const char http_content_type_binary[43]; +extern const char http_html[6]; +extern const char http_shtml[7]; +extern const char http_htm[5]; +extern const char http_css[5]; +extern const char http_png[5]; +extern const char http_gif[5]; +extern const char http_jpg[5]; +extern const char http_text[6]; +extern const char http_txt[5]; +extern const char http_user_agent_fields[77]; diff --git a/uip/apps/webclient/webclient.c b/uip/apps/webclient/webclient.c new file mode 100644 index 0000000..746c008 --- /dev/null +++ b/uip/apps/webclient/webclient.c @@ -0,0 +1,439 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup webclient Web client + * @{ + * + * This example shows a HTTP client that is able to download web pages + * and files from web servers. It requires a number of callback + * functions to be implemented by the module that utilizes the code: + * webclient_datahandler(), webclient_connected(), + * webclient_timedout(), webclient_aborted(), webclient_closed(). + */ + +/** + * \file + * Implementation of the HTTP client. + * \author Adam Dunkels <adam@dunkels.com> + */ + +/* + * Copyright (c) 2002, 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 notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: webclient.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "uip.h" +#include "uiplib.h" +#include "webclient.h" +#include "resolv.h" + +#include <string.h> + +#define WEBCLIENT_TIMEOUT 100 + +#define WEBCLIENT_STATE_STATUSLINE 0 +#define WEBCLIENT_STATE_HEADERS 1 +#define WEBCLIENT_STATE_DATA 2 +#define WEBCLIENT_STATE_CLOSE 3 + +#define HTTPFLAG_NONE 0 +#define HTTPFLAG_OK 1 +#define HTTPFLAG_MOVED 2 +#define HTTPFLAG_ERROR 3 + + +#define ISO_nl 0x0a +#define ISO_cr 0x0d +#define ISO_space 0x20 + + +static struct webclient_state s; + +/*-----------------------------------------------------------------------------------*/ +char * +webclient_mimetype(void) +{ + return s.mimetype; +} +/*-----------------------------------------------------------------------------------*/ +char * +webclient_filename(void) +{ + return s.file; +} +/*-----------------------------------------------------------------------------------*/ +char * +webclient_hostname(void) +{ + return s.host; +} +/*-----------------------------------------------------------------------------------*/ +unsigned short +webclient_port(void) +{ + return s.port; +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_init(void) +{ + +} +/*-----------------------------------------------------------------------------------*/ +static void +init_connection(void) +{ + s.state = WEBCLIENT_STATE_STATUSLINE; + + s.getrequestleft = sizeof(http_get) - 1 + 1 + + sizeof(http_10) - 1 + + sizeof(http_crnl) - 1 + + sizeof(http_host) - 1 + + sizeof(http_crnl) - 1 + + strlen(http_user_agent_fields) + + strlen(s.file) + strlen(s.host); + s.getrequestptr = 0; + + s.httpheaderlineptr = 0; +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_close(void) +{ + s.state = WEBCLIENT_STATE_CLOSE; +} +/*-----------------------------------------------------------------------------------*/ +unsigned char +webclient_get(char *host, u16_t port, char *file) +{ + struct uip_conn *conn; + uip_ipaddr_t *ipaddr; + static uip_ipaddr_t addr; + + /* First check if the host is an IP address. */ + ipaddr = &addr; + if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) { + ipaddr = (uip_ipaddr_t *)resolv_lookup(host); + + if(ipaddr == NULL) { + return 0; + } + } + + conn = uip_connect(ipaddr, htons(port)); + + if(conn == NULL) { + return 0; + } + + s.port = port; + strncpy(s.file, file, sizeof(s.file)); + strncpy(s.host, host, sizeof(s.host)); + + init_connection(); + return 1; +} +/*-----------------------------------------------------------------------------------*/ +static unsigned char * +copy_string(unsigned char *dest, + const unsigned char *src, unsigned char len) +{ + strncpy(dest, src, len); + return dest + len; +} +/*-----------------------------------------------------------------------------------*/ +static void +senddata(void) +{ + u16_t len; + char *getrequest; + char *cptr; + + if(s.getrequestleft > 0) { + cptr = getrequest = (char *)uip_appdata; + + cptr = copy_string(cptr, http_get, sizeof(http_get) - 1); + cptr = copy_string(cptr, s.file, strlen(s.file)); + *cptr++ = ISO_space; + cptr = copy_string(cptr, http_10, sizeof(http_10) - 1); + + cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1); + + cptr = copy_string(cptr, http_host, sizeof(http_host) - 1); + cptr = copy_string(cptr, s.host, strlen(s.host)); + cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1); + + cptr = copy_string(cptr, http_user_agent_fields, + strlen(http_user_agent_fields)); + + len = s.getrequestleft > uip_mss()? + uip_mss(): + s.getrequestleft; + uip_send(&(getrequest[s.getrequestptr]), len); + } +} +/*-----------------------------------------------------------------------------------*/ +static void +acked(void) +{ + u16_t len; + + if(s.getrequestleft > 0) { + len = s.getrequestleft > uip_mss()? + uip_mss(): + s.getrequestleft; + s.getrequestleft -= len; + s.getrequestptr += len; + } +} +/*-----------------------------------------------------------------------------------*/ +static u16_t +parse_statusline(u16_t len) +{ + char *cptr; + + while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) { + s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata; + ++((char *)uip_appdata); + --len; + if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) { + + if((strncmp(s.httpheaderline, http_10, + sizeof(http_10) - 1) == 0) || + (strncmp(s.httpheaderline, http_11, + sizeof(http_11) - 1) == 0)) { + cptr = &(s.httpheaderline[9]); + s.httpflag = HTTPFLAG_NONE; + if(strncmp(cptr, http_200, sizeof(http_200) - 1) == 0) { + /* 200 OK */ + s.httpflag = HTTPFLAG_OK; + } else if(strncmp(cptr, http_301, sizeof(http_301) - 1) == 0 || + strncmp(cptr, http_302, sizeof(http_302) - 1) == 0) { + /* 301 Moved permanently or 302 Found. Location: header line + will contain thw new location. */ + s.httpflag = HTTPFLAG_MOVED; + } else { + s.httpheaderline[s.httpheaderlineptr - 1] = 0; + } + } else { + uip_abort(); + webclient_aborted(); + return 0; + } + + /* We're done parsing the status line, so we reset the pointer + and start parsing the HTTP headers.*/ + s.httpheaderlineptr = 0; + s.state = WEBCLIENT_STATE_HEADERS; + break; + } else { + ++s.httpheaderlineptr; + } + } + return len; +} +/*-----------------------------------------------------------------------------------*/ +static char +casecmp(char *str1, const char *str2, char len) +{ + static char c; + + while(len > 0) { + c = *str1; + /* Force lower-case characters. */ + if(c & 0x40) { + c |= 0x20; + } + if(*str2 != c) { + return 1; + } + ++str1; + ++str2; + --len; + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +static u16_t +parse_headers(u16_t len) +{ + char *cptr; + static unsigned char i; + + while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) { + s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata; + ++((char *)uip_appdata); + --len; + if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) { + /* We have an entire HTTP header line in s.httpheaderline, so + we parse it. */ + if(s.httpheaderline[0] == ISO_cr) { + /* This was the last header line (i.e., and empty "\r\n"), so + we are done with the headers and proceed with the actual + data. */ + s.state = WEBCLIENT_STATE_DATA; + return len; + } + + s.httpheaderline[s.httpheaderlineptr - 1] = 0; + /* Check for specific HTTP header fields. */ + if(casecmp(s.httpheaderline, http_content_type, + sizeof(http_content_type) - 1) == 0) { + /* Found Content-type field. */ + cptr = strchr(s.httpheaderline, ';'); + if(cptr != NULL) { + *cptr = 0; + } + strncpy(s.mimetype, s.httpheaderline + + sizeof(http_content_type) - 1, sizeof(s.mimetype)); + } else if(casecmp(s.httpheaderline, http_location, + sizeof(http_location) - 1) == 0) { + cptr = s.httpheaderline + + sizeof(http_location) - 1; + + if(strncmp(cptr, http_http, 7) == 0) { + cptr += 7; + for(i = 0; i < s.httpheaderlineptr - 7; ++i) { + if(*cptr == 0 || + *cptr == '/' || + *cptr == ' ' || + *cptr == ':') { + s.host[i] = 0; + break; + } + s.host[i] = *cptr; + ++cptr; + } + } + strncpy(s.file, cptr, sizeof(s.file)); + /* s.file[s.httpheaderlineptr - i] = 0;*/ + } + + + /* We're done parsing, so we reset the pointer and start the + next line. */ + s.httpheaderlineptr = 0; + } else { + ++s.httpheaderlineptr; + } + } + return len; +} +/*-----------------------------------------------------------------------------------*/ +static void +newdata(void) +{ + u16_t len; + + len = uip_datalen(); + + if(s.state == WEBCLIENT_STATE_STATUSLINE) { + len = parse_statusline(len); + } + + if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) { + len = parse_headers(len); + } + + if(len > 0 && s.state == WEBCLIENT_STATE_DATA && + s.httpflag != HTTPFLAG_MOVED) { + webclient_datahandler((char *)uip_appdata, len); + } +} +/*-----------------------------------------------------------------------------------*/ +void +webclient_appcall(void) +{ + if(uip_connected()) { + s.timer = 0; + s.state = WEBCLIENT_STATE_STATUSLINE; + senddata(); + webclient_connected(); + return; + } + + if(s.state == WEBCLIENT_STATE_CLOSE) { + webclient_closed(); + uip_abort(); + return; + } + + if(uip_aborted()) { + webclient_aborted(); + } + if(uip_timedout()) { + webclient_timedout(); + } + + + if(uip_acked()) { + s.timer = 0; + acked(); + } + if(uip_newdata()) { + s.timer = 0; + newdata(); + } + if(uip_rexmit() || + uip_newdata() || + uip_acked()) { + senddata(); + } else if(uip_poll()) { + ++s.timer; + if(s.timer == WEBCLIENT_TIMEOUT) { + webclient_timedout(); + uip_abort(); + return; + } + /* senddata();*/ + } + + if(uip_closed()) { + if(s.httpflag != HTTPFLAG_MOVED) { + /* Send NULL data to signal EOF. */ + webclient_datahandler(NULL, 0); + } else { + if(resolv_lookup(s.host) == NULL) { + resolv_query(s.host); + } + webclient_get(s.host, s.port, s.file); + } + } +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/uip/apps/webclient/webclient.h b/uip/apps/webclient/webclient.h new file mode 100644 index 0000000..44cb95c --- /dev/null +++ b/uip/apps/webclient/webclient.h @@ -0,0 +1,228 @@ +/** + * \addtogroup webclient + * @{ + */ + +/** + * \file + * Header file for the HTTP client. + * \author Adam Dunkels <adam@dunkels.com> + */ + +/* + * Copyright (c) 2002, 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 notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: webclient.h,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ +#ifndef __WEBCLIENT_H__ +#define __WEBCLIENT_H__ + + +#include "webclient-strings.h" +#include "uipopt.h" + +#define WEBCLIENT_CONF_MAX_URLLEN 100 + +struct webclient_state { + u8_t timer; + u8_t state; + u8_t httpflag; + + u16_t port; + char host[40]; + char file[WEBCLIENT_CONF_MAX_URLLEN]; + u16_t getrequestptr; + u16_t getrequestleft; + + char httpheaderline[200]; + u16_t httpheaderlineptr; + + char mimetype[32]; +}; + +typedef struct webclient_state uip_tcp_appstate_t; +#define UIP_APPCALL webclient_appcall + +/** + * Callback function that is called from the webclient code when HTTP + * data has been received. + * + * This function must be implemented by the module that uses the + * webclient code. The function is called from the webclient module + * when HTTP data has been received. The function is not called when + * HTTP headers are received, only for the actual data. + * + * \note This function is called many times, repetedly, when data is + * being received, and not once when all data has been received. + * + * \param data A pointer to the data that has been received. + * \param len The length of the data that has been received. + */ +void webclient_datahandler(char *data, u16_t len); + +/** + * Callback function that is called from the webclient code when the + * HTTP connection has been connected to the web server. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_connected(void); + +/** + * Callback function that is called from the webclient code if the + * HTTP connection to the web server has timed out. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_timedout(void); + +/** + * Callback function that is called from the webclient code if the + * HTTP connection to the web server has been aborted by the web + * server. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_aborted(void); + +/** + * Callback function that is called from the webclient code when the + * HTTP connection to the web server has been closed. + * + * This function must be implemented by the module that uses the + * webclient code. + */ +void webclient_closed(void); + + + +/** + * Initialize the webclient module. + */ +void webclient_init(void); + +/** + * Open an HTTP connection to a web server and ask for a file using + * the GET method. + * + * This function opens an HTTP connection to the specified web server + * and requests the specified file using the GET method. When the HTTP + * connection has been connected, the webclient_connected() callback + * function is called and when the HTTP data arrives the + * webclient_datahandler() callback function is called. + * + * The callback function webclient_timedout() is called if the web + * server could not be contacted, and the webclient_aborted() callback + * function is called if the HTTP connection is aborted by the web + * server. + * + * When the HTTP request has been completed and the HTTP connection is + * closed, the webclient_closed() callback function will be called. + * + * \note If the function is passed a host name, it must already be in + * the resolver cache in order for the function to connect to the web + * server. It is therefore up to the calling module to implement the + * resolver calls and the signal handler used for reporting a resolv + * query answer. + * + * \param host A pointer to a string containing either a host name or + * a numerical IP address in dotted decimal notation (e.g., 192.168.23.1). + * + * \param port The port number to which to connect, in host byte order. + * + * \param file A pointer to the name of the file to get. + * + * \retval 0 if the host name could not be found in the cache, or + * if a TCP connection could not be created. + * + * \retval 1 if the connection was initiated. + */ +unsigned char webclient_get(char *host, u16_t port, char *file); + +/** + * Close the currently open HTTP connection. + */ +void webclient_close(void); +void webclient_appcall(void); + +/** + * Obtain the MIME type of the current HTTP data stream. + * + * \return A pointer to a string contaning the MIME type. The string + * may be empty if no MIME type was reported by the web server. + */ +char *webclient_mimetype(void); + +/** + * Obtain the filename of the current HTTP data stream. + * + * The filename of an HTTP request may be changed by the web server, + * and may therefore not be the same as when the original GET request + * was made with webclient_get(). This function is used for obtaining + * the current filename. + * + * \return A pointer to the current filename. + */ +char *webclient_filename(void); + +/** + * Obtain the hostname of the current HTTP data stream. + * + * The hostname of the web server of an HTTP request may be changed + * by the web server, and may therefore not be the same as when the + * original GET request was made with webclient_get(). This function + * is used for obtaining the current hostname. + * + * \return A pointer to the current hostname. + */ +char *webclient_hostname(void); + +/** + * Obtain the port number of the current HTTP data stream. + * + * The port number of an HTTP request may be changed by the web + * server, and may therefore not be the same as when the original GET + * request was made with webclient_get(). This function is used for + * obtaining the current port number. + * + * \return The port number of the current HTTP data stream, in host byte order. + */ +unsigned short webclient_port(void); + + + +#endif /* __WEBCLIENT_H__ */ + +/** @} */ diff --git a/uip/apps/webserver/Makefile.webserver b/uip/apps/webserver/Makefile.webserver new file mode 100644 index 0000000..7d3e086 --- /dev/null +++ b/uip/apps/webserver/Makefile.webserver @@ -0,0 +1 @@ +APP_SOURCES += httpd.c http-strings.c httpd-fs.c httpd-cgi.c diff --git a/uip/apps/webserver/http-strings b/uip/apps/webserver/http-strings new file mode 100644 index 0000000..d0b9121 --- /dev/null +++ b/uip/apps/webserver/http-strings @@ -0,0 +1,35 @@ +http_http "http://" +http_200 "200 " +http_301 "301 " +http_302 "302 " +http_get "GET " +http_10 "HTTP/1.0" +http_11 "HTTP/1.1" +http_content_type "content-type: " +http_texthtml "text/html" +http_location "location: " +http_host "host: " +http_crnl "\r\n" +http_index_html "/index.html" +http_404_html "/404.html" +http_referer "Referer:" +http_header_200 "HTTP/1.0 200 OK\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" +http_header_404 "HTTP/1.0 404 Not found\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" +http_content_type_plain "Content-type: text/plain\r\n\r\n" +http_content_type_html "Content-type: text/html\r\n\r\n" +http_content_type_css "Content-type: text/css\r\n\r\n" +http_content_type_text "Content-type: text/text\r\n\r\n" +http_content_type_png "Content-type: image/png\r\n\r\n" +http_content_type_gif "Content-type: image/gif\r\n\r\n" +http_content_type_jpg "Content-type: image/jpeg\r\n\r\n" +http_content_type_binary "Content-type: application/octet-stream\r\n\r\n" +http_html ".html" +http_shtml ".shtml" +http_htm ".htm" +http_css ".css" +http_png ".png" +http_gif ".gif" +http_jpg ".jpg" +http_text ".txt" +http_txt ".txt" + diff --git a/uip/apps/webserver/http-strings.c b/uip/apps/webserver/http-strings.c new file mode 100644 index 0000000..0d822ba --- /dev/null +++ b/uip/apps/webserver/http-strings.c @@ -0,0 +1,102 @@ +const char http_http[8] = +/* "http://" */ +{0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, }; +const char http_200[5] = +/* "200 " */ +{0x32, 0x30, 0x30, 0x20, }; +const char http_301[5] = +/* "301 " */ +{0x33, 0x30, 0x31, 0x20, }; +const char http_302[5] = +/* "302 " */ +{0x33, 0x30, 0x32, 0x20, }; +const char http_get[5] = +/* "GET " */ +{0x47, 0x45, 0x54, 0x20, }; +const char http_10[9] = +/* "HTTP/1.0" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, }; +const char http_11[9] = +/* "HTTP/1.1" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, }; +const char http_content_type[15] = +/* "content-type: " */ +{0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, }; +const char http_texthtml[10] = +/* "text/html" */ +{0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_location[11] = +/* "location: " */ +{0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, }; +const char http_host[7] = +/* "host: " */ +{0x68, 0x6f, 0x73, 0x74, 0x3a, 0x20, }; +const char http_crnl[3] = +/* "\r\n" */ +{0xd, 0xa, }; +const char http_index_html[12] = +/* "/index.html" */ +{0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_404_html[10] = +/* "/404.html" */ +{0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_referer[9] = +/* "Referer:" */ +{0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x3a, }; +const char http_header_200[84] = +/* "HTTP/1.0 200 OK\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, }; +const char http_header_404[91] = +/* "HTTP/1.0 404 Not found\r\nServer: uIP/1.0 http://www.sics.se/~adam/uip/\r\nConnection: close\r\n" */ +{0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x34, 0x30, 0x34, 0x20, 0x4e, 0x6f, 0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0xd, 0xa, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 0x70, 0x2f, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0xd, 0xa, }; +const char http_content_type_plain[29] = +/* "Content-type: text/plain\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_html[28] = +/* "Content-type: text/html\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_css [27] = +/* "Content-type: text/css\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_text[28] = +/* "Content-type: text/text\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x74, 0x65, 0x78, 0x74, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_png [28] = +/* "Content-type: image/png\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_gif [28] = +/* "Content-type: image/gif\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_jpg [29] = +/* "Content-type: image/jpeg\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x65, 0x67, 0xd, 0xa, 0xd, 0xa, }; +const char http_content_type_binary[43] = +/* "Content-type: application/octet-stream\r\n\r\n" */ +{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0xd, 0xa, 0xd, 0xa, }; +const char http_html[6] = +/* ".html" */ +{0x2e, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_shtml[7] = +/* ".shtml" */ +{0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, }; +const char http_htm[5] = +/* ".htm" */ +{0x2e, 0x68, 0x74, 0x6d, }; +const char http_css[5] = +/* ".css" */ +{0x2e, 0x63, 0x73, 0x73, }; +const char http_png[5] = +/* ".png" */ +{0x2e, 0x70, 0x6e, 0x67, }; +const char http_gif[5] = +/* ".gif" */ +{0x2e, 0x67, 0x69, 0x66, }; +const char http_jpg[5] = +/* ".jpg" */ +{0x2e, 0x6a, 0x70, 0x67, }; +const char http_text[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, }; +const char http_txt[5] = +/* ".txt" */ +{0x2e, 0x74, 0x78, 0x74, }; diff --git a/uip/apps/webserver/http-strings.h b/uip/apps/webserver/http-strings.h new file mode 100644 index 0000000..f121dd7 --- /dev/null +++ b/uip/apps/webserver/http-strings.h @@ -0,0 +1,34 @@ +extern const char http_http[8]; +extern const char http_200[5]; +extern const char http_301[5]; +extern const char http_302[5]; +extern const char http_get[5]; +extern const char http_10[9]; +extern const char http_11[9]; +extern const char http_content_type[15]; +extern const char http_texthtml[10]; +extern const char http_location[11]; +extern const char http_host[7]; +extern const char http_crnl[3]; +extern const char http_index_html[12]; +extern const char http_404_html[10]; +extern const char http_referer[9]; +extern const char http_header_200[84]; +extern const char http_header_404[91]; +extern const char http_content_type_plain[29]; +extern const char http_content_type_html[28]; +extern const char http_content_type_css [27]; +extern const char http_content_type_text[28]; +extern const char http_content_type_png [28]; +extern const char http_content_type_gif [28]; +extern const char http_content_type_jpg [29]; +extern const char http_content_type_binary[43]; +extern const char http_html[6]; +extern const char http_shtml[7]; +extern const char http_htm[5]; +extern const char http_css[5]; +extern const char http_png[5]; +extern const char http_gif[5]; +extern const char http_jpg[5]; +extern const char http_text[5]; +extern const char http_txt[5]; diff --git a/uip/apps/webserver/httpd-cgi.c b/uip/apps/webserver/httpd-cgi.c new file mode 100644 index 0000000..6257035 --- /dev/null +++ b/uip/apps/webserver/httpd-cgi.c @@ -0,0 +1,203 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * Web server script interface + * \author + * Adam Dunkels <adam@sics.se> + * + */ + +/* + * Copyright (c) 2001-2006, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd-cgi.c,v 1.2 2006/06/11 21:46:37 adam Exp $ + * + */ + +#include "uip.h" +#include "psock.h" +#include "httpd.h" +#include "httpd-cgi.h" +#include "httpd-fs.h" + +#include <stdio.h> +#include <string.h> + +HTTPD_CGI_CALL(file, "file-stats", file_stats); +HTTPD_CGI_CALL(tcp, "tcp-connections", tcp_stats); +HTTPD_CGI_CALL(net, "net-stats", net_stats); + +static const struct httpd_cgi_call *calls[] = { &file, &tcp, &net, NULL }; + +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(nullfunction(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +httpd_cgifunction +httpd_cgi(char *name) +{ + const struct httpd_cgi_call **f; + + /* Find the matching name in the table, return the function. */ + for(f = calls; *f != NULL; ++f) { + if(strncmp((*f)->name, name, strlen((*f)->name)) == 0) { + return (*f)->function; + } + } + return nullfunction; +} +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_file_stats(void *arg) +{ + char *f = (char *)arg; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, "%5u", httpd_fs_count(f)); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(file_stats(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + + PSOCK_GENERATOR_SEND(&s->sout, generate_file_stats, strchr(ptr, ' ') + 1); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static const char closed[] = /* "CLOSED",*/ +{0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0}; +static const char syn_rcvd[] = /* "SYN-RCVD",*/ +{0x53, 0x59, 0x4e, 0x2d, 0x52, 0x43, 0x56, + 0x44, 0}; +static const char syn_sent[] = /* "SYN-SENT",*/ +{0x53, 0x59, 0x4e, 0x2d, 0x53, 0x45, 0x4e, + 0x54, 0}; +static const char established[] = /* "ESTABLISHED",*/ +{0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, + 0x45, 0x44, 0}; +static const char fin_wait_1[] = /* "FIN-WAIT-1",*/ +{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, + 0x54, 0x2d, 0x31, 0}; +static const char fin_wait_2[] = /* "FIN-WAIT-2",*/ +{0x46, 0x49, 0x4e, 0x2d, 0x57, 0x41, 0x49, + 0x54, 0x2d, 0x32, 0}; +static const char closing[] = /* "CLOSING",*/ +{0x43, 0x4c, 0x4f, 0x53, 0x49, + 0x4e, 0x47, 0}; +static const char time_wait[] = /* "TIME-WAIT,"*/ +{0x54, 0x49, 0x4d, 0x45, 0x2d, 0x57, 0x41, + 0x49, 0x54, 0}; +static const char last_ack[] = /* "LAST-ACK"*/ +{0x4c, 0x41, 0x53, 0x54, 0x2d, 0x41, 0x43, + 0x4b, 0}; + +static const char *states[] = { + closed, + syn_rcvd, + syn_sent, + established, + fin_wait_1, + fin_wait_2, + closing, + time_wait, + last_ack}; + + +static unsigned short +generate_tcp_stats(void *arg) +{ + struct uip_conn *conn; + struct httpd_state *s = (struct httpd_state *)arg; + + conn = &uip_conns[s->count]; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, + "<tr><td>%d</td><td>%u.%u.%u.%u:%u</td><td>%s</td><td>%u</td><td>%u</td><td>%c %c</td></tr>\r\n", + htons(conn->lport), + htons(conn->ripaddr[0]) >> 8, + htons(conn->ripaddr[0]) & 0xff, + htons(conn->ripaddr[1]) >> 8, + htons(conn->ripaddr[1]) & 0xff, + htons(conn->rport), + states[conn->tcpstateflags & UIP_TS_MASK], + conn->nrtx, + conn->timer, + (uip_outstanding(conn))? '*':' ', + (uip_stopped(conn))? '!':' '); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(tcp_stats(struct httpd_state *s, char *ptr)) +{ + + PSOCK_BEGIN(&s->sout); + + for(s->count = 0; s->count < UIP_CONNS; ++s->count) { + if((uip_conns[s->count].tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { + PSOCK_GENERATOR_SEND(&s->sout, generate_tcp_stats, s); + } + } + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_net_stats(void *arg) +{ + struct httpd_state *s = (struct httpd_state *)arg; + return snprintf((char *)uip_appdata, UIP_APPDATA_SIZE, + "%5u\n", ((uip_stats_t *)&uip_stat)[s->count]); +} + +static +PT_THREAD(net_stats(struct httpd_state *s, char *ptr)) +{ + PSOCK_BEGIN(&s->sout); + +#if UIP_STATISTICS + + for(s->count = 0; s->count < sizeof(uip_stat) / sizeof(uip_stats_t); + ++s->count) { + PSOCK_GENERATOR_SEND(&s->sout, generate_net_stats, s); + } + +#endif /* UIP_STATISTICS */ + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/uip/apps/webserver/httpd-cgi.h b/uip/apps/webserver/httpd-cgi.h new file mode 100644 index 0000000..e6ba51e --- /dev/null +++ b/uip/apps/webserver/httpd-cgi.h @@ -0,0 +1,84 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * Web server script interface header file + * \author + * Adam Dunkels <adam@sics.se> + * + */ + + + +/* + * Copyright (c) 2001, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd-cgi.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ + +#ifndef __HTTPD_CGI_H__ +#define __HTTPD_CGI_H__ + +#include "psock.h" +#include "httpd.h" + +typedef PT_THREAD((* httpd_cgifunction)(struct httpd_state *, char *)); + +httpd_cgifunction httpd_cgi(char *name); + +struct httpd_cgi_call { + const char *name; + const httpd_cgifunction function; +}; + +/** + * \brief HTTPD CGI function declaration + * \param name The C variable name of the function + * \param str The string name of the function, used in the script file + * \param function A pointer to the function that implements it + * + * This macro is used for declaring a HTTPD CGI + * function. This function is then added to the list of + * HTTPD CGI functions with the httpd_cgi_add() function. + * + * \hideinitializer + */ +#define HTTPD_CGI_CALL(name, str, function) \ +static PT_THREAD(function(struct httpd_state *, char *)); \ +static const struct httpd_cgi_call name = {str, function} + +void httpd_cgi_init(void); +#endif /* __HTTPD_CGI_H__ */ + +/** @} */ diff --git a/uip/apps/webserver/httpd-fs.c b/uip/apps/webserver/httpd-fs.c new file mode 100644 index 0000000..21185e8 --- /dev/null +++ b/uip/apps/webserver/httpd-fs.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: httpd-fs.c,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ + +#include "httpd.h" +#include "httpd-fs.h" +#include "httpd-fsdata.h" + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +#include "httpd-fsdata.c" + +#if HTTPD_FS_STATISTICS +static u16_t count[HTTPD_FS_NUMFILES]; +#endif /* HTTPD_FS_STATISTICS */ + +/*-----------------------------------------------------------------------------------*/ +static u8_t +httpd_fs_strcmp(const char *str1, const char *str2) +{ + u8_t i; + i = 0; + loop: + + if(str2[i] == 0 || + str1[i] == '\r' || + str1[i] == '\n') { + return 0; + } + + if(str1[i] != str2[i]) { + return 1; + } + + + ++i; + goto loop; +} +/*-----------------------------------------------------------------------------------*/ +int +httpd_fs_open(const char *name, struct httpd_fs_file *file) +{ +#if HTTPD_FS_STATISTICS + u16_t i = 0; +#endif /* HTTPD_FS_STATISTICS */ + struct httpd_fsdata_file_noconst *f; + + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) { + + if(httpd_fs_strcmp(name, f->name) == 0) { + file->data = f->data; + file->len = f->len; +#if HTTPD_FS_STATISTICS + ++count[i]; +#endif /* HTTPD_FS_STATISTICS */ + return 1; + } +#if HTTPD_FS_STATISTICS + ++i; +#endif /* HTTPD_FS_STATISTICS */ + + } + return 0; +} +/*-----------------------------------------------------------------------------------*/ +void +httpd_fs_init(void) +{ +#if HTTPD_FS_STATISTICS + u16_t i; + for(i = 0; i < HTTPD_FS_NUMFILES; i++) { + count[i] = 0; + } +#endif /* HTTPD_FS_STATISTICS */ +} +/*-----------------------------------------------------------------------------------*/ +#if HTTPD_FS_STATISTICS +u16_t httpd_fs_count +(char *name) +{ + struct httpd_fsdata_file_noconst *f; + u16_t i; + + i = 0; + for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT; + f != NULL; + f = (struct httpd_fsdata_file_noconst *)f->next) { + + if(httpd_fs_strcmp(name, f->name) == 0) { + return count[i]; + } + ++i; + } + return 0; +} +#endif /* HTTPD_FS_STATISTICS */ +/*-----------------------------------------------------------------------------------*/ diff --git a/uip/apps/webserver/httpd-fs.h b/uip/apps/webserver/httpd-fs.h new file mode 100644 index 0000000..d80ed3d --- /dev/null +++ b/uip/apps/webserver/httpd-fs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: httpd-fs.h,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ +#ifndef __HTTPD_FS_H__ +#define __HTTPD_FS_H__ + +#define HTTPD_FS_STATISTICS 1 + +struct httpd_fs_file { + char *data; + int len; +}; + +/* 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); + +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 +u16_t httpd_fs_count(char *name); +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ + +void httpd_fs_init(void); + +#endif /* __HTTPD_FS_H__ */ diff --git a/uip/apps/webserver/httpd-fs/404.html b/uip/apps/webserver/httpd-fs/404.html new file mode 100644 index 0000000..a17711d --- /dev/null +++ b/uip/apps/webserver/httpd-fs/404.html @@ -0,0 +1,8 @@ +<html> + <body bgcolor="white"> + <center> + <h1>404 - file not found</h1> + <h3>Go <a href="/">here</a> instead.</h3> + </center> + </body> +</html>
\ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/fade.png b/uip/apps/webserver/httpd-fs/fade.png Binary files differnew file mode 100644 index 0000000..a9e69f7 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/fade.png diff --git a/uip/apps/webserver/httpd-fs/files.shtml b/uip/apps/webserver/httpd-fs/files.shtml new file mode 100644 index 0000000..811e230 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/files.shtml @@ -0,0 +1,35 @@ +%!: /header.html +<h1>File statistics</h1> +<center> +<table width="300"> +<tr><td><a href="/index.html">/index.html</a></td> +<td>%! file-stats /index.html +</td><td><img src="/fade.png" height=10 width=%! file-stats /index.html +> </td></tr> +<tr><td><a href="/files.shtml">/files.shtml</a></td> +<td>%! file-stats /files.shtml +</td><td><img src="/fade.png" height=10 width=%! file-stats /files.shtml +> </td></tr> +<tr><td><a href="/tcp.shtml">/tcp.shtml</a></td> +<td>%! file-stats /tcp.shtml +</td><td><img src="/fade.png" height=10 width=%! file-stats /tcp.shtml +> </td></tr> +<tr><td><a href="/stats.shtml">/stats.shtml</a></td> +<td>%! file-stats /stats.shtml +</td><td><img src="/fade.png" height=10 width=%! file-stats /stats.shtml +> </td></tr> +<tr><td><a href="/style.css">/style.css</a></td> +<td>%! file-stats /style.css +</td><td><img src="/fade.png" height=10 width=%! file-stats /style.css +> </td></tr> +<tr><td><a href="/404.html">/404.html</a></td> +<td>%! file-stats /404.html +</td><td><img src="/fade.png" height=10 width=%! file-stats /404.html +> </td></tr> +<tr><td><a href="/fade.png">/fade.png</a></td> +<td>%! file-stats /fade.png +</td><td><img src="/fade.png" height=10 width=%! file-stats /fade.png +> </td></tr> +</table> +</center> +%!: /footer.html diff --git a/uip/apps/webserver/httpd-fs/footer.html b/uip/apps/webserver/httpd-fs/footer.html new file mode 100644 index 0000000..1fd5f4f --- /dev/null +++ b/uip/apps/webserver/httpd-fs/footer.html @@ -0,0 +1,2 @@ + </body> +</html>
\ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/header.html b/uip/apps/webserver/httpd-fs/header.html new file mode 100644 index 0000000..7b1a1fe --- /dev/null +++ b/uip/apps/webserver/httpd-fs/header.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <title>Welcome to the uIP web server!</title> + <link rel="stylesheet" type="text/css" href="style.css"> + </head> + <body bgcolor="#fffeec" text="black"> + + <div class="menu"> + <div class="menubox"><a href="/">Front page</a></div> + <div class="menubox"><a href="files.shtml">File statistics</a></div> + <div class="menubox"><a href="stats.shtml">Network statistics</a></div> + <div class="menubox"><a href="tcp.shtml">Network + connections</a></div> + <br> + </div> + + <div class="contentblock"> diff --git a/uip/apps/webserver/httpd-fs/index.html b/uip/apps/webserver/httpd-fs/index.html new file mode 100644 index 0000000..27cbc93 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/index.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <title>Welcome to the uIP web server!</title> + <link rel="stylesheet" type="text/css" href="style.css"> + </head> + <body bgcolor="#fffeec" text="black"> + + <div class="menu"> + <div class="menubox"><a href="/">Front page</a></div> + <div class="menubox"><a href="files.shtml">File statistics</a></div> + <div class="menubox"><a href="stats.shtml">Network statistics</a></div> + <div class="menubox"><a href="tcp.shtml">Network + connections</a></div> + <br> + </div> + + <div class="contentblock"> + <p> + These web pages are served by a small web server running on top of + the <a href="http://www.sics.se/~adam/uip/">uIP embedded TCP/IP + stack</a>. + </p> + <p> + Click on the links above for web server statistics. + </p> + + </body> +</html> diff --git a/uip/apps/webserver/httpd-fs/processes.shtml b/uip/apps/webserver/httpd-fs/processes.shtml new file mode 100644 index 0000000..2f93e35 --- /dev/null +++ b/uip/apps/webserver/httpd-fs/processes.shtml @@ -0,0 +1,5 @@ +%!: /header.html +<h1>System processes</h1><br><table width="100%"> +<tr><th>ID</th><th>Name</th><th>Priority</th><th>Poll handler</th><th>Event handler</th><th>Procstate</th></tr> +%! processes +%!: /footer.html
\ No newline at end of file diff --git a/uip/apps/webserver/httpd-fs/stats.shtml b/uip/apps/webserver/httpd-fs/stats.shtml new file mode 100644 index 0000000..c63ed4a --- /dev/null +++ b/uip/apps/webserver/httpd-fs/stats.shtml @@ -0,0 +1,31 @@ +%!: /header.html +<h1>Network statistics</h1> +<center> +<table width="300" border="0"> +<tr><td><pre> +IP Packets received + Packets sent + Packets dropped +IP errors IP version/header length + IP length, high byte + IP length, low byte + IP fragments + Header checksum + Wrong protocol +ICMP Packets received + Packets sent + Packets dropped + Type errors +TCP Packets received + Packets sent + Packets dropped + Checksum errors + Data packets without ACKs + Resets + Retransmissions + No connection avaliable + Connection attempts to closed ports +</pre></td><td><pre>%! net-stats +</pre></table> +</center> +%!: /footer.html diff --git a/uip/apps/webserver/httpd-fs/style.css b/uip/apps/webserver/httpd-fs/style.css new file mode 100644 index 0000000..ba6df7f --- /dev/null +++ b/uip/apps/webserver/httpd-fs/style.css @@ -0,0 +1,92 @@ +h1 +{ + text-align: center; + font-size:14pt; + font-family:arial,helvetica; + font-weight:bold; + padding:10px; +} + +body +{ + + background-color: #fffeec; + color:black; + + font-size:8pt; + font-family:arial,helvetica; +} + +.menu +{ + margin: 4px; + width:60%; + + padding:2px; + + border: solid 1px; + background-color: #fffcd2; + text-align:left; + + font-size:9pt; + font-family:arial,helvetica; +} + +div.menubox +{ + width: 25%; + border: 0; + float: left; +text-align: center; +} + +.contentblock +{ + margin: 4px; + width:60%; + + padding:2px; + + border: 1px dotted; + background-color: white; + + font-size:8pt; + font-family:arial,helvetica; + +} + +p.intro +{ + margin-left:20px; + margin-right:20px; + + font-size:10pt; +/* font-weight:bold; */ + font-family:arial,helvetica; +} + +p.clink +{ + font-size:12pt; + font-family:courier,monospace; + text-align:center; +} + +p.clink9 +{ + font-size:9pt; + font-family:courier,monospace; + text-align:center; +} + + +p +{ + padding-left:10px; +} + +p.right +{ + text-align:right; +} + diff --git a/uip/apps/webserver/httpd-fs/tcp.shtml b/uip/apps/webserver/httpd-fs/tcp.shtml new file mode 100644 index 0000000..4c4bffe --- /dev/null +++ b/uip/apps/webserver/httpd-fs/tcp.shtml @@ -0,0 +1,5 @@ +%!: /header.html +<h1>Current connections</h1><br><table width="100%"> +<tr><th>Local</th><th>Remote</th><th>State</th><th>Retransmissions</th><th>Timer</th><th>Flags</th></tr> +%! tcp-connections +%!: /footer.html
\ No newline at end of file diff --git a/uip/apps/webserver/httpd-fsdata.c b/uip/apps/webserver/httpd-fsdata.c new file mode 100644 index 0000000..491095e --- /dev/null +++ b/uip/apps/webserver/httpd-fsdata.c @@ -0,0 +1,607 @@ +static const unsigned char data_processes_shtml[] = { + /* /processes.shtml */ + 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x70, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3c, 0x2f, 0x68, + 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, + 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x49, 0x44, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4e, 0x61, 0x6d, 0x65, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x3c, 0x2f, 0x74, + 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, 0x6f, 0x6c, 0x6c, + 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x50, + 0x72, 0x6f, 0x63, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, + 0x21, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, 0x6f, 0x6f, + 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0}; + +static const unsigned char data_404_html[] = { + /* /404.html */ + 0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 0x22, + 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x63, 0x65, 0x6e, + 0x74, 0x65, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x3c, 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, + 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x33, + 0x3e, 0x47, 0x6f, 0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x68, 0x65, 0x72, 0x65, + 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x2e, 0x3c, 0x2f, 0x68, 0x33, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, + 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, +0}; + +static const unsigned char data_files_shtml[] = { + /* /files.shtml */ + 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x68, 0x31, + 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, + 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, 0x30, 0x22, 0x3e, + 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, + 0x3e, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, + 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, + 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, + 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, + 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, + 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x20, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, + 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, + 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, + 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, + 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, + 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, + 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, + 0x20, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x72, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, + 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, + 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, + 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, + 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x74, 0x63, 0x70, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, + 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, + 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, + 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, 0x63, + 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, + 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3d, + 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x25, + 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, 0x61, + 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, + 0x73, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x2f, 0x73, + 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, 0x79, + 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0xa, 0x3c, 0x2f, 0x74, + 0x64, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, + 0x20, 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, + 0x74, 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, + 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0xa, 0x3e, 0x20, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, + 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, + 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x34, + 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x2f, + 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3c, 0x2f, + 0x61, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, + 0x64, 0x3e, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, + 0x73, 0x72, 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, + 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, + 0x73, 0x74, 0x61, 0x74, 0x73, 0x20, 0x2f, 0x34, 0x30, 0x34, + 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3e, 0x20, 0x3c, 0x2f, + 0x74, 0x64, 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, + 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x64, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, + 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x22, 0x3e, 0x2f, 0x66, 0x61, + 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0x3c, 0x2f, 0x61, 0x3e, + 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0xa, 0x3c, 0x74, 0x64, 0x3e, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0xa, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x73, 0x72, + 0x63, 0x3d, 0x22, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, + 0x6e, 0x67, 0x22, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3d, 0x31, 0x30, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, + 0x25, 0x21, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2d, 0x73, 0x74, + 0x61, 0x74, 0x73, 0x20, 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, + 0x70, 0x6e, 0x67, 0xa, 0x3e, 0x20, 0x3c, 0x2f, 0x74, 0x64, + 0x3e, 0x3c, 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x3c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x3e, 0xa, 0x3c, 0x2f, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x3a, 0x20, + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, + 0x6d, 0x6c, 0xa, 0}; + +static const unsigned char data_footer_html[] = { + /* /footer.html */ + 0x2f, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x20, 0x20, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, + 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0}; + +static const unsigned char data_header_html[] = { + /* /header.html */ + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0xa, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0xa, 0x20, + 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x3d, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0}; + +static const unsigned char data_index_html[] = { + /* /index.html */ + 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, + 0x48, 0x54, 0x4d, 0x4c, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, + 0x43, 0x20, 0x22, 0x2d, 0x2f, 0x2f, 0x57, 0x33, 0x43, 0x2f, + 0x2f, 0x44, 0x54, 0x44, 0x20, 0x48, 0x54, 0x4d, 0x4c, 0x20, + 0x34, 0x2e, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x2f, 0x45, + 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x34, + 0x2f, 0x6c, 0x6f, 0x6f, 0x73, 0x65, 0x2e, 0x64, 0x74, 0x64, + 0x22, 0x3e, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x49, 0x50, 0x20, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x21, + 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x3c, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x72, + 0x65, 0x6c, 0x3d, 0x22, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, + 0x68, 0x65, 0x65, 0x74, 0x22, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x63, 0x73, 0x73, + 0x22, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0x22, 0x3e, 0x20, + 0x20, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, + 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, + 0x62, 0x67, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x23, + 0x66, 0x66, 0x66, 0x65, 0x65, 0x63, 0x22, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x3d, 0x22, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x22, + 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, + 0x75, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, + 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x2f, 0x22, 0x3e, 0x46, + 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, + 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, + 0x3d, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x68, + 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x46, 0x69, 0x6c, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, + 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, + 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, 0x65, 0x6e, 0x75, 0x62, + 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, + 0x66, 0x3d, 0x22, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, + 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, + 0x64, 0x69, 0x76, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x64, 0x69, + 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x6d, + 0x65, 0x6e, 0x75, 0x62, 0x6f, 0x78, 0x22, 0x3e, 0x3c, 0x61, + 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x74, 0x63, 0x70, + 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0x22, 0x3e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0xa, 0x20, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3c, + 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, + 0x20, 0x20, 0x3c, 0x62, 0x72, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x64, 0x69, 0x76, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, + 0x64, 0x69, 0x76, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, + 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x70, + 0x3e, 0xa, 0x20, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x77, 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x73, 0x6d, 0x61, 0x6c, + 0x6c, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6f, 0x66, + 0xa, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x3c, 0x61, 0x20, + 0x68, 0x72, 0x65, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x69, 0x63, + 0x73, 0x2e, 0x73, 0x65, 0x2f, 0x7e, 0x61, 0x64, 0x61, 0x6d, + 0x2f, 0x75, 0x69, 0x70, 0x2f, 0x22, 0x3e, 0x75, 0x49, 0x50, + 0x20, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x54, 0x43, 0x50, 0x2f, 0x49, 0x50, 0xa, 0x20, 0x20, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x3c, 0x2f, 0x61, 0x3e, 0x2e, 0xa, + 0x20, 0x20, 0x3c, 0x2f, 0x70, 0x3e, 0xa, 0x20, 0x20, 0x3c, + 0x70, 0x3e, 0xa, 0x20, 0x20, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x20, 0x61, 0x62, 0x6f, 0x76, 0x65, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0xa, 0x20, 0x20, 0x3c, + 0x2f, 0x70, 0x3e, 0xa, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x62, + 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, + 0x6c, 0x3e, 0xa, 0}; + +static const unsigned char data_style_css[] = { + /* /style.css */ + 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x2e, 0x63, 0x73, 0x73, 0, + 0x68, 0x31, 0x20, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x34, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, + 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, + 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, + 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0xa, 0x20, 0x20, 0x70, + 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x31, 0x30, 0x70, + 0x78, 0x3b, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x62, 0x6f, 0x64, + 0x79, 0xa, 0x7b, 0xa, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, + 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, 0x65, + 0x65, 0x63, 0x3b, 0xa, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3a, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x3b, 0xa, 0xa, + 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, + 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, + 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, + 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0xa, 0x7d, 0xa, + 0xa, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0xa, 0x7b, 0xa, 0x20, + 0x20, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, + 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x36, 0x30, 0x25, 0x3b, 0xa, 0xa, 0x20, 0x20, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, + 0x78, 0x3b, 0xa, 0x9, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x3a, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, + 0x20, 0x31, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, + 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x66, 0x66, + 0x63, 0x64, 0x32, 0x3b, 0xa, 0x20, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x6c, 0x65, + 0x66, 0x74, 0x3b, 0xa, 0x20, 0x20, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, + 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, + 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, + 0x69, 0x61, 0x6c, 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, + 0x69, 0x63, 0x61, 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 0xa, + 0x64, 0x69, 0x76, 0x2e, 0x6d, 0x65, 0x6e, 0x75, 0x62, 0x6f, + 0x78, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3a, 0x20, 0x32, 0x35, 0x25, 0x3b, 0xa, 0x20, 0x20, + 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x20, 0x30, 0x3b, + 0xa, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3a, 0x20, + 0x6c, 0x65, 0x66, 0x74, 0x3b, 0xa, 0x74, 0x65, 0x78, 0x74, + 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x20, 0x63, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, 0xa, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0xa, 0x7b, 0x20, 0x20, 0xa, 0x20, 0x20, 0x6d, + 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x34, 0x70, 0x78, + 0x3b, 0xa, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, + 0x36, 0x30, 0x25, 0x3b, 0xa, 0xa, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x32, 0x70, 0x78, 0x3b, + 0xa, 0xa, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x3a, 0x20, 0x31, 0x70, 0x78, 0x20, 0x64, 0x6f, 0x74, 0x74, + 0x65, 0x64, 0x3b, 0xa, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6b, + 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x3a, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3b, + 0xa, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, + 0x69, 0x7a, 0x65, 0x3a, 0x38, 0x70, 0x74, 0x3b, 0xa, 0x20, + 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x68, + 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x3b, 0x20, + 0x20, 0xa, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x69, 0x6e, + 0x74, 0x72, 0x6f, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x6c, 0x65, 0x66, 0x74, 0x3a, + 0x32, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x20, 0x20, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x3a, 0x32, 0x30, 0x70, 0x78, 0x3b, 0xa, 0xa, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, + 0x31, 0x30, 0x70, 0x74, 0x3b, 0xa, 0x2f, 0x2a, 0x20, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3a, 0x62, 0x6f, 0x6c, 0x64, 0x3b, 0x20, 0x2a, 0x2f, + 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x61, 0x72, 0x69, 0x61, 0x6c, + 0x2c, 0x68, 0x65, 0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, + 0x3b, 0x20, 0x20, 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x63, + 0x6c, 0x69, 0x6e, 0x6b, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, + 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, + 0x32, 0x70, 0x74, 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, + 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, + 0x6f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0xa, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, + 0xa, 0x7d, 0xa, 0xa, 0x70, 0x2e, 0x63, 0x6c, 0x69, 0x6e, + 0x6b, 0x39, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, + 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x39, 0x70, 0x74, + 0x3b, 0xa, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x63, 0x6f, 0x75, 0x72, + 0x69, 0x65, 0x72, 0x2c, 0x6d, 0x6f, 0x6e, 0x6f, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x3b, 0x20, 0x20, 0xa, 0x20, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, + 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3b, 0xa, 0x7d, 0xa, + 0xa, 0xa, 0x70, 0xa, 0x7b, 0xa, 0x20, 0x20, 0x70, 0x61, + 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6c, 0x65, 0x66, 0x74, + 0x3a, 0x31, 0x30, 0x70, 0x78, 0x3b, 0xa, 0x7d, 0xa, 0xa, + 0x70, 0x2e, 0x72, 0x69, 0x67, 0x68, 0x74, 0xa, 0x7b, 0xa, + 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, + 0x67, 0x6e, 0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3b, 0x20, + 0xa, 0x7d, 0xa, 0xa, 0}; + +static const unsigned char data_tcp_shtml[] = { + /* /tcp.shtml */ + 0x2f, 0x74, 0x63, 0x70, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x62, 0x72, 0x3e, 0x3c, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x64, 0x74, + 0x68, 0x3d, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x3e, 0xa, + 0x3c, 0x74, 0x72, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, + 0x68, 0x3e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3c, 0x2f, + 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, + 0x3e, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x3c, 0x2f, 0x74, 0x68, + 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x54, 0x69, 0x6d, 0x65, 0x72, + 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, 0x74, 0x68, 0x3e, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x3c, 0x2f, 0x74, 0x68, 0x3e, 0x3c, + 0x2f, 0x74, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x20, 0x74, 0x63, + 0x70, 0x2d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, + 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, +0}; + +static const unsigned char data_fade_png[] = { + /* /fade.png */ + 0x2f, 0x66, 0x61, 0x64, 0x65, 0x2e, 0x70, 0x6e, 0x67, 0, + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 00, 00, + 00, 0xd, 0x49, 0x48, 0x44, 0x52, 00, 00, 00, 0x4, + 00, 00, 00, 0xa, 0x8, 0x2, 00, 00, 00, 0x1c, + 0x99, 0x68, 0x59, 00, 00, 00, 0x9, 0x70, 0x48, 0x59, + 0x73, 00, 00, 0xb, 0x13, 00, 00, 0xb, 0x13, 0x1, + 00, 0x9a, 0x9c, 0x18, 00, 00, 00, 0x7, 0x74, 0x49, + 0x4d, 0x45, 0x7, 0xd6, 0x6, 0x8, 0x14, 0x1b, 0x39, 0xaf, + 0x5b, 0xc0, 0xe3, 00, 00, 00, 0x1d, 0x74, 0x45, 0x58, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 00, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4d, 0x50, + 0xef, 0x64, 0x25, 0x6e, 00, 00, 00, 0x3a, 0x49, 0x44, + 0x41, 0x54, 0x8, 0xd7, 0x75, 0x8c, 0x31, 0x12, 00, 0x10, + 0x10, 0xc4, 0x2e, 0x37, 0x9e, 0x40, 0x65, 0xfd, 0xff, 0x83, + 0xf4, 0xa, 0x1c, 0x8d, 0x54, 0x9b, 0xc9, 0xcc, 0x9a, 0x3d, + 0x90, 0x73, 0x71, 0x67, 0x91, 0xd4, 0x74, 0x36, 0xa9, 0x55, + 0x1, 0xf8, 0x29, 0x58, 0xc8, 0xbf, 0x48, 0xc4, 0x81, 0x74, + 0xb, 0xa3, 0xf, 0x7c, 0xdb, 0x4, 0xe8, 0x40, 0x5, 0xdf, + 0xa1, 0xf3, 0xfc, 0x73, 00, 00, 00, 00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0}; + +static const unsigned char data_stats_shtml[] = { + /* /stats.shtml */ + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x2e, 0x73, 0x68, 0x74, 0x6d, 0x6c, 0, + 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0xa, 0x3c, 0x68, 0x31, + 0x3e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x3c, + 0x2f, 0x68, 0x31, 0x3e, 0xa, 0x3c, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0xa, 0x3c, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x33, 0x30, + 0x30, 0x22, 0x20, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3d, + 0x22, 0x30, 0x22, 0x3e, 0xa, 0x3c, 0x74, 0x72, 0x3e, 0x3c, + 0x74, 0x64, 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0xa, 0x49, + 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, + 0x73, 0x65, 0x6e, 0x74, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x49, 0x50, 0x20, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x20, 0x20, 0x20, 0x20, + 0x49, 0x50, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, + 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x2c, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x20, 0x62, 0x79, 0x74, 0x65, 0xa, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x49, 0x50, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x2c, 0x20, 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x79, 0x74, + 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x50, 0x20, 0x66, 0x72, + 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x57, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0xa, 0x49, 0x43, 0x4d, 0x50, 0x9, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x54, 0x79, 0x70, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0xa, 0x54, 0x43, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0xa, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x20, 0x64, + 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0xa, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x20, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, + 0x61, 0x74, 0x61, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, + 0x41, 0x43, 0x4b, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x73, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x4e, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x76, 0x61, 0x6c, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0xa, 0x9, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x20, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0xa, 0x3c, 0x2f, 0x70, 0x72, + 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x64, 0x3e, 0x3c, 0x74, 0x64, + 0x3e, 0x3c, 0x70, 0x72, 0x65, 0x3e, 0x25, 0x21, 0x20, 0x6e, + 0x65, 0x74, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x73, 0xa, 0x3c, + 0x2f, 0x70, 0x72, 0x65, 0x3e, 0x3c, 0x2f, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x3e, 0xa, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x3e, 0xa, 0x25, 0x21, 0x3a, 0x20, 0x2f, 0x66, + 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x2e, 0x68, 0x74, 0x6d, 0x6c, + 0xa, 0}; + +const struct httpd_fsdata_file file_processes_shtml[] = {{NULL, data_processes_shtml, data_processes_shtml + 17, sizeof(data_processes_shtml) - 17}}; + +const struct httpd_fsdata_file file_404_html[] = {{file_processes_shtml, data_404_html, data_404_html + 10, sizeof(data_404_html) - 10}}; + +const struct httpd_fsdata_file file_files_shtml[] = {{file_404_html, data_files_shtml, data_files_shtml + 13, sizeof(data_files_shtml) - 13}}; + +const struct httpd_fsdata_file file_footer_html[] = {{file_files_shtml, data_footer_html, data_footer_html + 13, sizeof(data_footer_html) - 13}}; + +const struct httpd_fsdata_file file_header_html[] = {{file_footer_html, data_header_html, data_header_html + 13, sizeof(data_header_html) - 13}}; + +const struct httpd_fsdata_file file_index_html[] = {{file_header_html, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12}}; + +const struct httpd_fsdata_file file_style_css[] = {{file_index_html, data_style_css, data_style_css + 11, sizeof(data_style_css) - 11}}; + +const struct httpd_fsdata_file file_tcp_shtml[] = {{file_style_css, data_tcp_shtml, data_tcp_shtml + 11, sizeof(data_tcp_shtml) - 11}}; + +const struct httpd_fsdata_file file_fade_png[] = {{file_tcp_shtml, data_fade_png, data_fade_png + 10, sizeof(data_fade_png) - 10}}; + +const struct httpd_fsdata_file file_stats_shtml[] = {{file_fade_png, data_stats_shtml, data_stats_shtml + 13, sizeof(data_stats_shtml) - 13}}; + +#define HTTPD_FS_ROOT file_stats_shtml + +#define HTTPD_FS_NUMFILES 10 diff --git a/uip/apps/webserver/httpd-fsdata.h b/uip/apps/webserver/httpd-fsdata.h new file mode 100644 index 0000000..0ad2d6e --- /dev/null +++ b/uip/apps/webserver/httpd-fsdata.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: httpd-fsdata.h,v 1.1 2006/06/07 09:13:08 adam Exp $ + */ +#ifndef __HTTPD_FSDATA_H__ +#define __HTTPD_FSDATA_H__ + +#include "uip.h" + +struct httpd_fsdata_file { + const struct httpd_fsdata_file *next; + const char *name; + const char *data; + const int len; +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 + u16_t count; +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ +}; + +struct httpd_fsdata_file_noconst { + struct httpd_fsdata_file *next; + char *name; + char *data; + int len; +#ifdef HTTPD_FS_STATISTICS +#if HTTPD_FS_STATISTICS == 1 + u16_t count; +#endif /* HTTPD_FS_STATISTICS */ +#endif /* HTTPD_FS_STATISTICS */ +}; + +#endif /* __HTTPD_FSDATA_H__ */ diff --git a/uip/apps/webserver/httpd.c b/uip/apps/webserver/httpd.c new file mode 100644 index 0000000..937e138 --- /dev/null +++ b/uip/apps/webserver/httpd.c @@ -0,0 +1,338 @@ +/** + * \addtogroup apps + * @{ + */ + +/** + * \defgroup httpd Web server + * @{ + * The uIP web server is a very simplistic implementation of an HTTP + * server. It can serve web pages and files from a read-only ROM + * filesystem, and provides a very small scripting language. + + */ + +/** + * \file + * Web server + * \author + * Adam Dunkels <adam@sics.se> + */ + + +/* + * Copyright (c) 2004, 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the uIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $ + */ + +#include "uip.h" +#include "httpd.h" +#include "httpd-fs.h" +#include "httpd-cgi.h" +#include "http-strings.h" + +#include <string.h> + +#define STATE_WAITING 0 +#define STATE_OUTPUT 1 + +#define ISO_nl 0x0a +#define ISO_space 0x20 +#define ISO_bang 0x21 +#define ISO_percent 0x25 +#define ISO_period 0x2e +#define ISO_slash 0x2f +#define ISO_colon 0x3a + + +/*---------------------------------------------------------------------------*/ +static unsigned short +generate_part_of_file(void *state) +{ + struct httpd_state *s = (struct httpd_state *)state; + + if(s->file.len > uip_mss()) { + s->len = uip_mss(); + } else { + s->len = s->file.len; + } + memcpy(uip_appdata, s->file.data, s->len); + + return s->len; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_file(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sout); + + do { + PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s); + s->file.len -= s->len; + s->file.data += s->len; + } while(s->file.len > 0); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_part_of_file(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sout); + + PSOCK_SEND(&s->sout, s->file.data, s->len); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static void +next_scriptstate(struct httpd_state *s) +{ + char *p; + p = strchr(s->scriptptr, ISO_nl) + 1; + s->scriptlen -= (unsigned short)(p - s->scriptptr); + s->scriptptr = p; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_script(struct httpd_state *s)) +{ + char *ptr; + + PT_BEGIN(&s->scriptpt); + + + while(s->file.len > 0) { + + /* Check if we should start executing a script. */ + if(*s->file.data == ISO_percent && + *(s->file.data + 1) == ISO_bang) { + s->scriptptr = s->file.data + 3; + s->scriptlen = s->file.len - 3; + if(*(s->scriptptr - 1) == ISO_colon) { + httpd_fs_open(s->scriptptr + 1, &s->file); + PT_WAIT_THREAD(&s->scriptpt, send_file(s)); + } else { + PT_WAIT_THREAD(&s->scriptpt, + httpd_cgi(s->scriptptr)(s, s->scriptptr)); + } + next_scriptstate(s); + + /* The script is over, so we reset the pointers and continue + sending the rest of the file. */ + s->file.data = s->scriptptr; + s->file.len = s->scriptlen; + } else { + /* See if we find the start of script marker in the block of HTML + to be sent. */ + + if(s->file.len > uip_mss()) { + s->len = uip_mss(); + } else { + s->len = s->file.len; + } + + if(*s->file.data == ISO_percent) { + ptr = strchr(s->file.data + 1, ISO_percent); + } else { + ptr = strchr(s->file.data, ISO_percent); + } + if(ptr != NULL && + ptr != s->file.data) { + s->len = (int)(ptr - s->file.data); + if(s->len >= uip_mss()) { + s->len = uip_mss(); + } + } + PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); + s->file.data += s->len; + s->file.len -= s->len; + + } + } + + PT_END(&s->scriptpt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) +{ + char *ptr; + + PSOCK_BEGIN(&s->sout); + + PSOCK_SEND_STR(&s->sout, statushdr); + + ptr = strrchr(s->filename, ISO_period); + if(ptr == NULL) { + PSOCK_SEND_STR(&s->sout, http_content_type_binary); + } else if(strncmp(http_html, ptr, 5) == 0 || + strncmp(http_shtml, ptr, 6) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_html); + } else if(strncmp(http_css, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_css); + } else if(strncmp(http_png, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_png); + } else if(strncmp(http_gif, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_gif); + } else if(strncmp(http_jpg, ptr, 4) == 0) { + PSOCK_SEND_STR(&s->sout, http_content_type_jpg); + } else { + PSOCK_SEND_STR(&s->sout, http_content_type_plain); + } + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_output(struct httpd_state *s)) +{ + char *ptr; + + PT_BEGIN(&s->outputpt); + + if(!httpd_fs_open(s->filename, &s->file)) { + httpd_fs_open(http_404_html, &s->file); + strcpy(s->filename, http_404_html); + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, + http_header_404)); + PT_WAIT_THREAD(&s->outputpt, + send_file(s)); + } else { + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, + http_header_200)); + ptr = strchr(s->filename, ISO_period); + if(ptr != NULL && strncmp(ptr, http_shtml, 6) == 0) { + PT_INIT(&s->scriptpt); + PT_WAIT_THREAD(&s->outputpt, handle_script(s)); + } else { + PT_WAIT_THREAD(&s->outputpt, + send_file(s)); + } + } + PSOCK_CLOSE(&s->sout); + PT_END(&s->outputpt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_input(struct httpd_state *s)) +{ + PSOCK_BEGIN(&s->sin); + + PSOCK_READTO(&s->sin, ISO_space); + + + if(strncmp(s->inputbuf, http_get, 4) != 0) { + PSOCK_CLOSE_EXIT(&s->sin); + } + PSOCK_READTO(&s->sin, ISO_space); + + if(s->inputbuf[0] != ISO_slash) { + PSOCK_CLOSE_EXIT(&s->sin); + } + + if(s->inputbuf[1] == ISO_space) { + strncpy(s->filename, http_index_html, sizeof(s->filename)); + } else { + s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; + strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename)); + } + + /* httpd_log_file(uip_conn->ripaddr, s->filename);*/ + + s->state = STATE_OUTPUT; + + while(1) { + PSOCK_READTO(&s->sin, ISO_nl); + + if(strncmp(s->inputbuf, http_referer, 8) == 0) { + s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0; + /* httpd_log(&s->inputbuf[9]);*/ + } + } + + PSOCK_END(&s->sin); +} +/*---------------------------------------------------------------------------*/ +static void +handle_connection(struct httpd_state *s) +{ + handle_input(s); + if(s->state == STATE_OUTPUT) { + handle_output(s); + } +} +/*---------------------------------------------------------------------------*/ +void +httpd_appcall(void) +{ + struct httpd_state *s = (struct httpd_state *)&(uip_conn->appstate); + + if(uip_closed() || uip_aborted() || uip_timedout()) { + } else if(uip_connected()) { + PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1); + PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1); + PT_INIT(&s->outputpt); + s->state = STATE_WAITING; + /* timer_set(&s->timer, CLOCK_SECOND * 100);*/ + s->timer = 0; + handle_connection(s); + } else if(s != NULL) { + if(uip_poll()) { + ++s->timer; + if(s->timer >= 20) { + uip_abort(); + } + } else { + s->timer = 0; + } + handle_connection(s); + } else { + uip_abort(); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialize the web server + * + * 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/uip/apps/webserver/httpd.h b/uip/apps/webserver/httpd.h new file mode 100644 index 0000000..270d49d --- /dev/null +++ b/uip/apps/webserver/httpd.h @@ -0,0 +1,62 @@ +/* + * 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 + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: httpd.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ + +#ifndef __HTTPD_H__ +#define __HTTPD_H__ + +#include "psock.h" +#include "httpd-fs.h" + +struct httpd_state { + unsigned char timer; + struct psock sin, sout; + struct pt outputpt, scriptpt; + char inputbuf[50]; + char filename[20]; + char state; + struct httpd_fs_file file; + int len; + char *scriptptr; + int scriptlen; + + unsigned short count; +}; + +void httpd_init(void); +void httpd_appcall(void); + +void httpd_log(char *msg); +void httpd_log_file(u16_t *requester, char *file); + +#endif /* __HTTPD_H__ */ diff --git a/uip/apps/webserver/makefsdata b/uip/apps/webserver/makefsdata new file mode 100755 index 0000000..b2109ab --- /dev/null +++ b/uip/apps/webserver/makefsdata @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +open(OUTPUT, "> httpd-fsdata.c"); + +chdir("httpd-fs"); + +opendir(DIR, "."); +@files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); +closedir(DIR); + +foreach $file (@files) { + + if(-d $file && $file !~ /^\./) { + print "Processing directory $file\n"; + opendir(DIR, $file); + @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); + closedir(DIR); + printf "Adding files @newfiles\n"; + @files = (@files, map { $_ = "$file/$_" } @newfiles); + next; + } +} + +foreach $file (@files) { + if(-f $file) { + + print "Adding file $file\n"; + + open(FILE, $file) || die "Could not open file $file\n"; + + $file =~ s-^-/-; + $fvar = $file; + $fvar =~ s-/-_-g; + $fvar =~ s-\.-_-g; + # for AVR, add PROGMEM here + print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); + print(OUTPUT "\t/* $file */\n\t"); + for($j = 0; $j < length($file); $j++) { + printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); + } + printf(OUTPUT "0,\n"); + + + $i = 0; + while(read(FILE, $data, 1)) { + if($i == 0) { + print(OUTPUT "\t"); + } + printf(OUTPUT "%#02x, ", unpack("C", $data)); + $i++; + if($i == 10) { + print(OUTPUT "\n"); + $i = 0; + } + } + print(OUTPUT "0};\n\n"); + close(FILE); + push(@fvars, $fvar); + push(@pfiles, $file); + } +} + +for($i = 0; $i < @fvars; $i++) { + $file = $pfiles[$i]; + $fvar = $fvars[$i]; + + if($i == 0) { + $prevfile = "NULL"; + } else { + $prevfile = "file" . $fvars[$i - 1]; + } + print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); + print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); + print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); +} + +print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n"); +print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n"); diff --git a/uip/apps/webserver/makestrings b/uip/apps/webserver/makestrings new file mode 100755 index 0000000..20f0e24 --- /dev/null +++ b/uip/apps/webserver/makestrings @@ -0,0 +1,40 @@ +#!/usr/bin/perl + + +sub stringify { + my $name = shift(@_); + open(OUTPUTC, "> $name.c"); + open(OUTPUTH, "> $name.h"); + + open(FILE, "$name"); + + while(<FILE>) { + if(/(.+) "(.+)"/) { + $var = $1; + $data = $2; + + $datan = $data; + $datan =~ s/\\r/\r/g; + $datan =~ s/\\n/\n/g; + $datan =~ s/\\01/\01/g; + $datan =~ s/\\0/\0/g; + + printf(OUTPUTC "const char $var\[%d] = \n", length($datan) + 1); + printf(OUTPUTC "/* \"$data\" */\n"); + printf(OUTPUTC "{"); + for($j = 0; $j < length($datan); $j++) { + printf(OUTPUTC "%#02x, ", unpack("C", substr($datan, $j, 1))); + } + printf(OUTPUTC "};\n"); + + printf(OUTPUTH "extern const char $var\[%d];\n", length($datan) + 1); + + } + } + close(OUTPUTC); + close(OUTPUTH); +} +stringify("http-strings"); + +exit 0; + diff --git a/uip/apps/webserver/webserver.h b/uip/apps/webserver/webserver.h new file mode 100644 index 0000000..48753e6 --- /dev/null +++ b/uip/apps/webserver/webserver.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002, 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 notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + * + * This file is part of the uIP TCP/IP stack + * + * $Id: webserver.h,v 1.2 2006/06/11 21:46:38 adam Exp $ + * + */ +#ifndef __WEBSERVER_H__ +#define __WEBSERVER_H__ + +#include "httpd.h" + +typedef struct httpd_state uip_tcp_appstate_t; +/* UIP_APPCALL: the name of the application function. This function + must return void and take no arguments (i.e., C type "void + appfunc(void)"). */ +#ifndef UIP_APPCALL +#define UIP_APPCALL httpd_appcall +#endif + + +#endif /* __WEBSERVER_H__ */ |