From 8c49cf26e579aae7f203f41ec527c4b34d4af29d Mon Sep 17 00:00:00 2001 From: nifi Date: Sun, 9 May 2010 12:52:05 +0000 Subject: [PATCH] Added simple web server listing the neighbors and routes --- examples/ipv6/rpl-border-router/Makefile | 4 +- .../ipv6/rpl-border-router/border-router.c | 84 ++++++ .../ipv6/rpl-border-router/httpd-simple.c | 255 ++++++++++++++++++ .../ipv6/rpl-border-router/httpd-simple.h | 73 +++++ .../rpl-border-router/project-router-conf.h | 11 +- 5 files changed, 425 insertions(+), 2 deletions(-) create mode 100644 examples/ipv6/rpl-border-router/httpd-simple.c create mode 100644 examples/ipv6/rpl-border-router/httpd-simple.h diff --git a/examples/ipv6/rpl-border-router/Makefile b/examples/ipv6/rpl-border-router/Makefile index 827ab1238..1c60074c6 100644 --- a/examples/ipv6/rpl-border-router/Makefile +++ b/examples/ipv6/rpl-border-router/Makefile @@ -5,7 +5,9 @@ CONTIKI=../../.. WITH_UIP6=1 UIP_CONF_IPV6=1 +APPS += webserver + CFLAGS += -DPROJECT_CONF_H=\"project-router-conf.h\" -PROJECT_SOURCEFILES += slip-bridge.c +PROJECT_SOURCEFILES += slip-bridge.c httpd-simple.c include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6/rpl-border-router/border-router.c b/examples/ipv6/rpl-border-router/border-router.c index b6a30d01f..ff49269db 100644 --- a/examples/ipv6/rpl-border-router/border-router.c +++ b/examples/ipv6/rpl-border-router/border-router.c @@ -39,10 +39,13 @@ #include "contiki-lib.h" #include "contiki-net.h" #include "net/uip.h" +#include "net/uip-ds6.h" #include "net/rpl/rpl.h" #include "net/netstack.h" #include "dev/button-sensor.h" +#include "webserver-nogui.h" +#include "httpd-simple.h" #include #include #include @@ -53,9 +56,88 @@ uint16_t dag_id[] = {0x1111, 0x1100, 0, 0, 0, 0, 0, 0x0011}; +extern uip_ds6_nbr_t uip_ds6_nbr_cache[]; +extern uip_ds6_route_t uip_ds6_routing_table[]; + PROCESS(border_router_process, "Border router process"); AUTOSTART_PROCESSES(&border_router_process); /*---------------------------------------------------------------------------*/ +/* Only one single web request at time */ +static const char *TOP = "ContikiRPL\n"; +static const char *BOTTOM = "\n"; +static char buf[128]; +static int blen; +#define ADD(...) do { \ + blen += snprintf(&buf[blen], sizeof(buf) - blen, __VA_ARGS__); \ + } while(0) +/*---------------------------------------------------------------------------*/ +static void +ipaddr_add(const uip_ipaddr_t *addr) +{ + uint16_t a; + int i, f; + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { + a = (addr->u8[i] << 8) + addr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0 && sizeof(buf) - blen >= 2) { + buf[blen++] = ':'; + buf[blen++] = ':'; + } + } else { + if(f > 0) { + f = -1; + } else if(i > 0 && blen < sizeof(buf)) { + buf[blen++] = ':'; + } + ADD("%x", a); + } + } +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(generate_routes(struct httpd_state *s)) +{ + static int i; + PSOCK_BEGIN(&s->sout); + + SEND_STRING(&s->sout, TOP); + + blen = 0; + ADD("

Neighbors

"); + for(i = 0; i < UIP_DS6_NBR_NB; i++) { + if(uip_ds6_nbr_cache[i].isused) { + ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr); + ADD("
\n"); + SEND_STRING(&s->sout, buf); + blen = 0; + } + } + + ADD("

Routes

"); + for(i = 0; i < UIP_DS6_ROUTE_NB; i++) { + if(uip_ds6_routing_table[i].isused) { + ipaddr_add(&uip_ds6_routing_table[i].ipaddr); + ADD("
\n"); + SEND_STRING(&s->sout, buf); + blen = 0; + } + } + if(blen > 0) { + SEND_STRING(&s->sout, buf); + blen = 0; + } + + SEND_STRING(&s->sout, BOTTOM); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +httpd_simple_script_t +httpd_simple_get_script(const char *name) +{ + return generate_routes; +} +/*---------------------------------------------------------------------------*/ static void print_local_addresses(void) { @@ -85,6 +167,8 @@ PROCESS_THREAD(border_router_process, ev, data) PROCESS_PAUSE(); + process_start(&webserver_nogui_process, NULL); + SENSORS_ACTIVATE(button_sensor); PRINTF("RPL-Border router started\n"); diff --git a/examples/ipv6/rpl-border-router/httpd-simple.c b/examples/ipv6/rpl-border-router/httpd-simple.c new file mode 100644 index 000000000..f48c18b3e --- /dev/null +++ b/examples/ipv6/rpl-border-router/httpd-simple.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2010, 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. + * + * $Id: httpd-simple.c,v 1.1 2010/05/09 12:52:05 nifi Exp $ + */ + +/** + * \file + * A demo web server publishing sensor data + * \author + * Adam Dunkels + * Niclas Finne + * Joakim Eriksson + */ + +#include +#include + +#include "contiki-net.h" + +#include "webserver.h" +#include "lib/petsciiconv.h" +#include "http-strings.h" +#include "urlconv.h" + +#include "httpd-simple.h" + +#ifndef WEBSERVER_CONF_CFS_CONNS +#define CONNS UIP_CONNS +#else /* WEBSERVER_CONF_CFS_CONNS */ +#define CONNS WEBSERVER_CONF_CFS_CONNS +#endif /* WEBSERVER_CONF_CFS_CONNS */ + +#ifndef WEBSERVER_CONF_CFS_URLCONV +#define URLCONV 0 +#else /* WEBSERVER_CONF_CFS_URLCONV */ +#define URLCONV WEBSERVER_CONF_CFS_URLCONV +#endif /* WEBSERVER_CONF_CFS_URLCONV */ + +#define STATE_WAITING 0 +#define STATE_OUTPUT 1 + +MEMB(conns, struct httpd_state, CONNS); + +#define ISO_nl 0x0a +#define ISO_space 0x20 +#define ISO_period 0x2e +#define ISO_slash 0x2f + +/*---------------------------------------------------------------------------*/ +static const char *NOT_FOUND = "" +"
" +"

404 - file not found

" +"
" +"" +""; +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_string(struct httpd_state *s, const char *str)) +{ + PSOCK_BEGIN(&s->sout); + + SEND_STRING(&s->sout, str); + + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr)) +{ + /* char *ptr; */ + + PSOCK_BEGIN(&s->sout); + + SEND_STRING(&s->sout, statushdr); + + /* ptr = strrchr(s->filename, ISO_period); */ + /* if(ptr == NULL) { */ + /* s->ptr = http_content_type_plain; */ + /* } else if(strcmp(http_html, ptr) == 0) { */ + /* s->ptr = http_content_type_html; */ + /* } else if(strcmp(http_css, ptr) == 0) { */ + /* s->ptr = http_content_type_css; */ + /* } else if(strcmp(http_png, ptr) == 0) { */ + /* s->ptr = http_content_type_png; */ + /* } else if(strcmp(http_gif, ptr) == 0) { */ + /* s->ptr = http_content_type_gif; */ + /* } else if(strcmp(http_jpg, ptr) == 0) { */ + /* s->ptr = http_content_type_jpg; */ + /* } else { */ + /* s->ptr = http_content_type_binary; */ + /* } */ + /* SEND_STRING(&s->sout, s->ptr); */ + SEND_STRING(&s->sout, http_content_type_html); + PSOCK_END(&s->sout); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_output(struct httpd_state *s)) +{ + PT_BEGIN(&s->outputpt); + + s->script = NULL; + petsciiconv_topetscii(s->filename, sizeof(s->filename)); + s->script = httpd_simple_get_script(&s->filename[1]); + petsciiconv_toascii(s->filename, sizeof(s->filename)); + if(s->script == NULL) { + strcpy(s->filename, "/notfound.html"); + petsciiconv_toascii(s->filename, sizeof(s->filename)); + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, http_header_404)); + PT_WAIT_THREAD(&s->outputpt, + send_string(s, NOT_FOUND)); + uip_close(); + webserver_log_file(&uip_conn->ripaddr, "404 - not found"); + PT_EXIT(&s->outputpt); + } else { + PT_WAIT_THREAD(&s->outputpt, + send_headers(s, http_header_200)); + PT_WAIT_THREAD(&s->outputpt, s->script(s)); + } + s->script = NULL; + 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 URLCONV + s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0; + urlconv_tofilename(s->filename, s->inputbuf, sizeof(s->filename)); +#else /* URLCONV */ + 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, sizeof(s->filename)); + } +#endif /* URLCONV */ + + petsciiconv_topetscii(s->filename, sizeof(s->filename)); + webserver_log_file(&uip_conn->ripaddr, s->filename); + petsciiconv_toascii(s->filename, sizeof(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; + petsciiconv_topetscii(s->inputbuf, PSOCK_DATALEN(&s->sin) - 2); + webserver_log(s->inputbuf); + } + } + + 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 *state) +{ + struct httpd_state *s = (struct httpd_state *)state; + + if(uip_closed() || uip_aborted() || uip_timedout()) { + if(s != NULL) { + s->script = NULL; + memb_free(&conns, s); + } + } else if(uip_connected()) { + s = (struct httpd_state *)memb_alloc(&conns); + if(s == NULL) { + uip_abort(); + webserver_log_file(&uip_conn->ripaddr, "reset (no memory block)"); + return; + } + tcp_markconn(uip_conn, s); + PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); + PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1); + PT_INIT(&s->outputpt); + s->script = NULL; + s->state = STATE_WAITING; + timer_set(&s->timer, CLOCK_SECOND * 10); + handle_connection(s); + } else if(s != NULL) { + if(uip_poll()) { + if(timer_expired(&s->timer)) { + uip_abort(); + s->script = NULL; + memb_free(&conns, s); + webserver_log_file(&uip_conn->ripaddr, "reset (timeout)"); + } + } else { + timer_restart(&s->timer); + } + handle_connection(s); + } else { + uip_abort(); + } +} +/*---------------------------------------------------------------------------*/ +void +httpd_init(void) +{ + tcp_listen(HTONS(80)); + memb_init(&conns); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/ipv6/rpl-border-router/httpd-simple.h b/examples/ipv6/rpl-border-router/httpd-simple.h new file mode 100644 index 000000000..5fda299e8 --- /dev/null +++ b/examples/ipv6/rpl-border-router/httpd-simple.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, 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. + * + * $Id: httpd-simple.h,v 1.1 2010/05/09 12:52:05 nifi Exp $ + */ + +/** + * \file + * A simple webserver + * \author + * Adam Dunkels + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __HTTPD_SIMPLE_H__ +#define __HTTPD_SIMPLE_H__ + +#include "contiki-net.h" + +#ifndef WEBSERVER_CONF_CFS_PATHLEN +#define HTTPD_PATHLEN 80 +#else /* WEBSERVER_CONF_CFS_CONNS */ +#define HTTPD_PATHLEN WEBSERVER_CONF_CFS_PATHLEN +#endif /* WEBSERVER_CONF_CFS_CONNS */ + +struct httpd_state; +typedef char (* httpd_simple_script_t)(struct httpd_state *s); + +struct httpd_state { + struct timer timer; + struct psock sin, sout; + struct pt outputpt; + char inputbuf[HTTPD_PATHLEN + 30]; + char outputbuf[UIP_TCP_MSS]; + char filename[HTTPD_PATHLEN]; + httpd_simple_script_t script; + char state; +}; + +void httpd_init(void); +void httpd_appcall(void *state); + +httpd_simple_script_t httpd_simple_get_script(const char *name); + +#define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str)) + +#endif /* __HTTPD_SIMPLE_H__ */ diff --git a/examples/ipv6/rpl-border-router/project-router-conf.h b/examples/ipv6/rpl-border-router/project-router-conf.h index b8b16a990..3e6634e9e 100644 --- a/examples/ipv6/rpl-border-router/project-router-conf.h +++ b/examples/ipv6/rpl-border-router/project-router-conf.h @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: project-router-conf.h,v 1.2 2010/05/05 21:54:41 nifi Exp $ + * $Id: project-router-conf.h,v 1.3 2010/05/09 12:52:05 nifi Exp $ */ #ifndef __PROJECT_ROUTER_CONF_H__ @@ -46,4 +46,13 @@ #undef QUEUEBUF_CONF_NUM #define QUEUEBUF_CONF_NUM 6 +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 140 + +#undef UIP_CONF_RECEIVE_WINDOW +#define UIP_CONF_RECEIVE_WINDOW 60 + +#undef WEBSERVER_CONF_CFS_CONNS +#define WEBSERVER_CONF_CFS_CONNS 2 + #endif /* __PROJECT_ROUTER_CONF_H__ */