00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
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     
00060     s->len = cfs_read(s->fd, s->outputbuf, sizeof(s->outputbuf));
00061 
00062     
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   
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       
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