Contiki 2.6

httpd-cfs.c

00001 /*
00002  * Copyright (c) 2004, Adam Dunkels.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  *
00031  * Author: Adam Dunkels <adam@sics.se>
00032  *
00033  * $Id: httpd-cfs.c,v 1.2 2010/10/19 18:29:05 adamdunkels Exp $
00034  */
00035 
00036 #include <string.h>
00037 
00038 #include "contiki-net.h"
00039 
00040 #include "webserver.h"
00041 #include "cfs/cfs.h"
00042 #include "lib/petsciiconv.h"
00043 #include "http-strings.h"
00044 
00045 #include "httpd-cfs.h"
00046 
00047 #ifndef WEBSERVER_CONF_CFS_CONNS
00048 #define CONNS 4
00049 #else /* WEBSERVER_CONF_CFS_CONNS */
00050 #define CONNS WEBSERVER_CONF_CFS_CONNS
00051 #endif /* WEBSERVER_CONF_CFS_CONNS */
00052 
00053 #define STATE_WAITING 0
00054 #define STATE_OUTPUT  1
00055 
00056 #define SEND_STRING(s, str) PSOCK_SEND(s, (uint8_t *)str, strlen(str))
00057 MEMB(conns, struct httpd_state, CONNS);
00058 
00059 #define ISO_nl      0x0a
00060 #define ISO_space   0x20
00061 #define ISO_period  0x2e
00062 #define ISO_slash   0x2f
00063 
00064 /*---------------------------------------------------------------------------*/
00065 static
00066 PT_THREAD(send_file(struct httpd_state *s))
00067 {
00068   PSOCK_BEGIN(&s->sout);
00069   
00070   do {
00071     /* Read data from file system into buffer */
00072     s->len = cfs_read(s->fd, s->outputbuf, sizeof(s->outputbuf));
00073 
00074     /* If there is data in the buffer, send it */
00075     if(s->len > 0) {
00076       PSOCK_SEND(&s->sout, (uint8_t *)s->outputbuf, s->len);
00077     } else {
00078       break;
00079     }
00080   } while(s->len > 0);
00081       
00082   PSOCK_END(&s->sout);
00083 }
00084 /*---------------------------------------------------------------------------*/
00085 static
00086 PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
00087 {
00088   char *ptr;
00089 
00090   PSOCK_BEGIN(&s->sout);
00091 
00092   SEND_STRING(&s->sout, statushdr);
00093 
00094   ptr = strrchr(s->filename, ISO_period);
00095   if(ptr == NULL) {
00096     SEND_STRING(&s->sout, http_content_type_plain);
00097   } else if(strncmp(http_html, ptr, 5) == 0) {
00098     SEND_STRING(&s->sout, http_content_type_html);
00099   } else if(strncmp(http_css, ptr, 4) == 0) {
00100     SEND_STRING(&s->sout, http_content_type_css);
00101   } else if(strncmp(http_png, ptr, 4) == 0) {
00102     SEND_STRING(&s->sout, http_content_type_png);
00103   } else if(strncmp(http_jpg, ptr, 4) == 0) {
00104     SEND_STRING(&s->sout, http_content_type_jpg);
00105   } else {
00106     SEND_STRING(&s->sout, http_content_type_binary);
00107   }
00108   PSOCK_END(&s->sout);
00109 }
00110 /*---------------------------------------------------------------------------*/
00111 static
00112 PT_THREAD(handle_output(struct httpd_state *s))
00113 {
00114   PT_BEGIN(&s->outputpt);
00115 
00116   petsciiconv_topetscii(s->filename, sizeof(s->filename));
00117   s->fd = cfs_open(s->filename, CFS_READ);
00118   petsciiconv_toascii(s->filename, sizeof(s->filename));
00119   if(s->fd < 0) {
00120     s->fd = cfs_open("notfound.html", CFS_READ);
00121     if(s->fd < 0) {
00122       uip_abort();
00123       memb_free(&conns, s);
00124       webserver_log_file(&uip_conn->ripaddr, "reset (no notfound.html)");
00125       PT_EXIT(&s->outputpt);
00126     }
00127     PT_WAIT_THREAD(&s->outputpt,
00128                    send_headers(s, http_header_404));
00129   } else {
00130     PT_WAIT_THREAD(&s->outputpt,
00131                    send_headers(s, http_header_200));
00132   }
00133   PT_WAIT_THREAD(&s->outputpt, send_file(s));
00134   cfs_close(s->fd);
00135   s->fd = -1;
00136   PSOCK_CLOSE(&s->sout);
00137   PT_END(&s->outputpt);
00138 }
00139 /*---------------------------------------------------------------------------*/
00140 static
00141 PT_THREAD(handle_input(struct httpd_state *s))
00142 {
00143   PSOCK_BEGIN(&s->sin);
00144 
00145   PSOCK_READTO(&s->sin, ISO_space);
00146   
00147   if(strncmp(s->inputbuf, http_get, 4) != 0) {
00148     PSOCK_CLOSE_EXIT(&s->sin);
00149   }
00150   PSOCK_READTO(&s->sin, ISO_space);
00151 
00152   if(s->inputbuf[0] != ISO_slash) {
00153     PSOCK_CLOSE_EXIT(&s->sin);
00154   }
00155 
00156   if(s->inputbuf[1] == ISO_space) {
00157     strncpy(s->filename, &http_index_html[1], sizeof(s->filename));
00158   } else {
00159     s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00160     strncpy(s->filename, &s->inputbuf[1], sizeof(s->filename));
00161   }
00162 
00163   petsciiconv_topetscii(s->filename, sizeof(s->filename));
00164   webserver_log_file(&uip_conn->ripaddr, s->filename);
00165   petsciiconv_toascii(s->filename, sizeof(s->filename));
00166   s->state = STATE_OUTPUT;
00167 
00168   while(1) {
00169     PSOCK_READTO(&s->sin, ISO_nl);
00170 
00171     if(strncmp(s->inputbuf, http_referer, 8) == 0) {
00172       s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00173       petsciiconv_topetscii(s->inputbuf, PSOCK_DATALEN(&s->sin) - 2);
00174       webserver_log(s->inputbuf);
00175     }
00176   }
00177   
00178   PSOCK_END(&s->sin);
00179 }
00180 /*---------------------------------------------------------------------------*/
00181 static void
00182 handle_connection(struct httpd_state *s)
00183 {
00184   handle_input(s);
00185   if(s->state == STATE_OUTPUT) {
00186     handle_output(s);
00187   }
00188 }
00189 /*---------------------------------------------------------------------------*/
00190 void
00191 httpd_appcall(void *state)
00192 {
00193   struct httpd_state *s = (struct httpd_state *)state;
00194 
00195   if(uip_closed() || uip_aborted() || uip_timedout()) {
00196     if(s != NULL) {
00197       if(s->fd >= 0) {
00198         cfs_close(s->fd);
00199         s->fd = -1;
00200       }
00201       memb_free(&conns, s);
00202     }
00203   } else if(uip_connected()) {
00204     s = (struct httpd_state *)memb_alloc(&conns);
00205     if(s == NULL) {
00206       uip_abort();
00207       webserver_log_file(&uip_conn->ripaddr, "reset (no memory block)");
00208       return;
00209     }
00210     tcp_markconn(uip_conn, s);
00211     PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00212     PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00213     PT_INIT(&s->outputpt);
00214     s->fd = -1;
00215     s->state = STATE_WAITING;
00216     timer_set(&s->timer, CLOCK_SECOND * 10);
00217     handle_connection(s);
00218   } else if(s != NULL) {
00219     if(uip_poll()) {
00220       if(timer_expired(&s->timer)) {
00221         uip_abort();
00222         if(s->fd >= 0) {
00223           cfs_close(s->fd);
00224           s->fd = -1;
00225         }
00226         memb_free(&conns, s);
00227         webserver_log_file(&uip_conn->ripaddr, "reset (timeout)");
00228       }
00229     } else {
00230       timer_reset(&s->timer);
00231     }
00232     handle_connection(s);
00233   } else {
00234     uip_abort();
00235   }
00236 }
00237 /*---------------------------------------------------------------------------*/
00238 void
00239 httpd_init(void)
00240 {
00241   tcp_listen(UIP_HTONS(80));
00242   memb_init(&conns);
00243 }
00244 /*---------------------------------------------------------------------------*/