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 #include "cfs/cfs.h"
00040 
00041 #include "webserver.h"
00042 #include "libconio_arch-small.h"
00043 
00044 #include "httpd-cfs.h"
00045 
00046 #define STATE_WAITING 0
00047 #define STATE_OUTPUT  1
00048 
00049 #define SEND_STRING(s, str) PSOCK_SEND(s, str, strlen(str))
00050 MEMB(conns, struct httpd_state, 2);
00051 
00052 /*---------------------------------------------------------------------------*/
00053 static
00054 PT_THREAD(send_file(struct httpd_state *s))
00055 {
00056   PSOCK_BEGIN(&s->sout);
00057   
00058   do {
00059     /* Read data from file system into buffer */
00060     s->len = cfs_read(s->fd, s->outputbuf, sizeof(s->outputbuf));
00061 
00062     /* If there is data in the buffer, send it */
00063     if(s->len > 0) {
00064       PSOCK_SEND(&s->sout, s->outputbuf, s->len);
00065     } else {
00066       break;
00067     }
00068   } while(s->len > 0);
00069       
00070   PSOCK_END(&s->sout);
00071 }
00072 /*---------------------------------------------------------------------------*/
00073 static
00074 PT_THREAD(send_headers(struct httpd_state *s, char *statushdr))
00075 {
00076   char *ptr;
00077 
00078   PSOCK_BEGIN(&s->sout);
00079 
00080   SEND_STRING(&s->sout, statushdr);
00081   SEND_STRING(&s->sout, "Server: " CONTIKI_VERSION_STRING "\r\n");
00082 
00083   ptr = strrchr(s->filename, '.');
00084   if(ptr == NULL) {
00085     SEND_STRING(&s->sout, "Content-type: text/plain\r\n\r\n");
00086   } else if(strncmp(".html", ptr, 5) == 0) {
00087     SEND_STRING(&s->sout, "Content-type: text/html\r\n\r\n");
00088   } else if(strncmp(".css", ptr, 4) == 0) {
00089     SEND_STRING(&s->sout, "Content-type: text/css\r\n\r\n");
00090   } else if(strncmp(".png", ptr, 4) == 0) {
00091     SEND_STRING(&s->sout, "Content-type: image/png\r\n\r\n");
00092   } else if(strncmp(".jpg", ptr, 4) == 0) {
00093     SEND_STRING(&s->sout, "Content-type: image/jpeg\r\n\r\n");
00094   } else {
00095     SEND_STRING(&s->sout, "Content-type: application/octet-stream\r\n\r\n");
00096   }
00097   PSOCK_END(&s->sout);
00098 }
00099 /*---------------------------------------------------------------------------*/
00100 static
00101 PT_THREAD(handle_output(struct httpd_state *s))
00102 {
00103   PT_BEGIN(&s->outputpt);
00104 
00105   s->fd = cfs_open(s->filename, CFS_READ);
00106   if(s->fd < 0) {
00107     s->fd = cfs_open("404.html", CFS_READ);
00108     if(s->fd < 0) {
00109       uip_abort();
00110       PT_EXIT(&s->outputpt);
00111     }
00112     PT_WAIT_THREAD(&s->outputpt,
00113                    send_headers(s, "HTTP/1.0 404 Not found\r\n"));
00114     PT_WAIT_THREAD(&s->outputpt,
00115                    send_file(s));
00116   } else {
00117     PT_WAIT_THREAD(&s->outputpt,
00118                    send_headers(s, "HTTP/1.0 200 OK\r\n"));
00119     PT_WAIT_THREAD(&s->outputpt,
00120                    send_file(s));
00121     cfs_close(s->fd);
00122   }
00123   PSOCK_CLOSE(&s->sout);
00124   PT_END(&s->outputpt);
00125 }
00126 /*---------------------------------------------------------------------------*/
00127 static
00128 PT_THREAD(handle_input(struct httpd_state *s))
00129 {
00130   PSOCK_BEGIN(&s->sin);
00131 
00132   PSOCK_READTO(&s->sin, ' ');
00133   
00134   if(strncmp(s->inputbuf, "GET ", 4) != 0) {
00135     PSOCK_CLOSE_EXIT(&s->sin);
00136   }
00137   PSOCK_READTO(&s->sin, ' ');
00138 
00139   if(s->inputbuf[0] != '/') {
00140     PSOCK_CLOSE_EXIT(&s->sin);
00141   }
00142 
00143   if(s->inputbuf[1] == ' ') {
00144     strncpy(s->filename, "index.html", sizeof(s->filename));
00145   } else {
00146     s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00147     strncpy(s->filename, &s->inputbuf[1], sizeof(s->filename));
00148   }
00149 
00150   //  webserver_log_file(&uip_conn->ripaddr, s->filename);
00151   libputs_arch(s->filename);
00152   s->state = STATE_OUTPUT;
00153 
00154   while(1) {
00155     PSOCK_READTO(&s->sin, '\n');
00156 
00157     if(strncmp(s->inputbuf, "Referer:", 8) == 0) {
00158       s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
00159       libputs_arch(&s->inputbuf[9]);
00160       //      webserver_log(&s->inputbuf[9]);
00161     }
00162   }
00163   
00164   PSOCK_END(&s->sin);
00165 }
00166 /*---------------------------------------------------------------------------*/
00167 static void
00168 handle_connection(struct httpd_state *s)
00169 {
00170   handle_input(s);
00171   if(s->state == STATE_OUTPUT) {
00172     handle_output(s);
00173   }
00174 }
00175 /*---------------------------------------------------------------------------*/
00176 void
00177 httpd_appcall(void *state)
00178 {
00179   struct httpd_state *s = (struct httpd_state *)state;
00180 
00181   if(uip_closed() || uip_aborted() || uip_timedout()) {
00182     if(s != NULL) {
00183       memb_free(&conns, s);
00184     }
00185   } else if(uip_connected()) {
00186     s = (struct httpd_state *)memb_alloc(&conns);
00187     if(s == NULL) {
00188       uip_abort();
00189       return;
00190     }
00191     tcp_markconn(uip_conn, s);
00192     PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
00193     PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
00194     PT_INIT(&s->outputpt);
00195     s->state = STATE_WAITING;
00196     timer_set(&s->timer, CLOCK_SECOND * 10);
00197     handle_connection(s);
00198   } else if(s != NULL) {
00199     if(uip_poll()) {
00200       if(timer_expired(&s->timer)) {
00201         uip_abort();
00202       }
00203     } else {
00204       timer_reset(&s->timer);
00205     }
00206     handle_connection(s);
00207   } else {
00208     uip_abort();
00209   }
00210 }
00211 /*---------------------------------------------------------------------------*/
00212 void
00213 httpd_init(void)
00214 {
00215   tcp_listen(UIP_HTONS(80));
00216   memb_init(&conns);
00217 }
00218 /*---------------------------------------------------------------------------*/