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
00037
00038
00039
00040
00041
00042 #include <stdio.h>
00043 #include <string.h>
00044 #include <avr/pgmspace.h>
00045 #include "contiki-net.h"
00046
00047 #ifndef WEBSERVER_CONF_CFS_PATHLEN
00048 #define HTTPD_PATHLEN 2
00049 #else
00050 #define HTTPD_PATHLEN WEBSERVER_CONF_CFS_PATHLEN
00051 #endif
00052
00053 struct httpd_state;
00054 typedef char (* httpd_simple_script_t)(struct httpd_state *s);
00055
00056 struct httpd_state {
00057 struct timer timer;
00058 struct psock sin, sout;
00059 struct pt outputpt;
00060 char inputbuf[HTTPD_PATHLEN + 30];
00061 char outputbuf[UIP_TCP_MSS];
00062 char filename[HTTPD_PATHLEN];
00063 httpd_simple_script_t script;
00064 char state;
00065 };
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 #define DEBUGLOGIC 0
00079 #if DEBUGLOGIC
00080 struct httpd_state *sg;
00081 #define uip_mss(...) sizeof(uip_aligned_buf)
00082 #define uip_appdata (char *) &uip_aligned_buf
00083 #endif
00084
00085 #ifndef WEBSERVER_CONF_CFS_CONNS
00086 #define CONNS UIP_CONNS
00087 #else
00088 #define CONNS WEBSERVER_CONF_CFS_CONNS
00089 #endif
00090
00091 #ifndef WEBSERVER_CONF_CFS_URLCONV
00092 #define URLCONV 0
00093 #else
00094 #define URLCONV WEBSERVER_CONF_CFS_URLCONV
00095 #endif
00096
00097 #define STATE_WAITING 0
00098 #define STATE_OUTPUT 1
00099
00100 MEMB(conns, struct httpd_state, CONNS);
00101
00102 #define webserver_log_file(...)
00103
00104 #define ISO_nl 0x0a
00105 #define ISO_space 0x20
00106 #define ISO_period 0x2e
00107 #define ISO_slash 0x2f
00108
00109
00110 static unsigned short
00111 generate_string(void *sstr)
00112 {
00113 uint8_t slen=strlen((char *)sstr);
00114 memcpy(uip_appdata, (char *)sstr, slen);
00115
00116 #if DEBUGLOGIC
00117 return 0;
00118 #else
00119 return slen;
00120 #endif
00121 }
00122
00123 static unsigned short
00124 generate_string_P(void *sstr)
00125 {
00126 uint8_t slen=strlen_P((char *)sstr);
00127 memcpy_P(uip_appdata, (char *)sstr, slen);
00128
00129 #if DEBUGLOGIC
00130 return 0;
00131 #else
00132 return slen;
00133 #endif
00134 }
00135
00136 #if FIND_THE_SCRIPT
00137
00138
00139
00140 static
00141 PT_THREAD(send_string_P(struct httpd_state *s, char *str))
00142 {
00143 PSOCK_BEGIN(&s->sout);
00144 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, str);
00145 PSOCK_END(&s->sout);
00146 }
00147 #endif
00148
00149 char http_content_type_html[] PROGMEM = "Content-type: text/html\r\n\r\n";
00150 static
00151 PT_THREAD(send_headers(struct httpd_state *s, char *statushdr))
00152 {
00153 PSOCK_BEGIN(&s->sout);
00154 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, statushdr);
00155 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, http_content_type_html);
00156 PSOCK_END(&s->sout);
00157 }
00158
00159 const char http_index_html[] PROGMEM = "/index.html";
00160 const char http_referer[] PROGMEM = "Referer:";
00161 const char http_get[] PROGMEM = "GET ";
00162 static
00163 PT_THREAD(handle_input(struct httpd_state *s))
00164 {
00165 PSOCK_BEGIN(&s->sin);
00166
00167 PSOCK_READTO(&s->sin, ISO_space);
00168
00169 if(strncmp_P(s->inputbuf, http_get, 4) != 0) {
00170 PSOCK_CLOSE_EXIT(&s->sin);
00171 }
00172 PSOCK_READTO(&s->sin, ISO_space);
00173
00174 if(s->inputbuf[0] != ISO_slash) {
00175 PSOCK_CLOSE_EXIT(&s->sin);
00176 }
00177
00178 #if URLCONV
00179 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00180 urlconv_tofilename(s->filename, s->inputbuf, sizeof(s->filename));
00181 #else
00182 if(s->inputbuf[1] == ISO_space) {
00183 strncpy_P(s->filename, http_index_html, sizeof(s->filename));
00184 } else {
00185 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
00186 strncpy(s->filename, s->inputbuf, sizeof(s->filename));
00187 }
00188 #endif
00189
00190 webserver_log_file(&uip_conn->ripaddr, s->filename);
00191
00192 s->state = STATE_OUTPUT;
00193
00194 while(1) {
00195 PSOCK_READTO(&s->sin, ISO_nl);
00196
00197
00198
00199
00200
00201 }
00202
00203 PSOCK_END(&s->sin);
00204 }
00205
00206 void
00207 httpd_init(void)
00208 {
00209 tcp_listen(UIP_HTONS(80));
00210 memb_init(&conns);
00211 }
00212
00213
00214
00215 static char buf[48];
00216 static uint8_t blen;
00217 #define ADD(FORMAT,args...) do { \
00218 blen += snprintf_P(&buf[blen], sizeof(buf) - blen, PSTR(FORMAT),##args); \
00219 } while(0)
00220
00221 static void
00222 ipaddr_add(const uip_ipaddr_t *addr)
00223 {
00224 uint16_t a;
00225 int i, f;
00226 for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) {
00227 a = (addr->u8[i] << 8) + addr->u8[i + 1];
00228 if(a == 0 && f >= 0) {
00229 if(f++ == 0 && sizeof(buf) - blen >= 2) {
00230 buf[blen++] = ':';
00231 buf[blen++] = ':';
00232 }
00233 } else {
00234 if(f > 0) {
00235 f = -1;
00236 } else if(i > 0 && blen < sizeof(buf)) {
00237 buf[blen++] = ':';
00238 }
00239 ADD("%x", a);
00240 }
00241 }
00242 }
00243
00244 char TOP1[] PROGMEM = "<html><head><title>ContikiRPL(Jackdaw)";
00245 char TOP2[] PROGMEM = "</title></head><body>";
00246 char BOTTOM[] PROGMEM = "</body></html>";
00247 #if UIP_CONF_IPV6
00248 extern uip_ds6_nbr_t uip_ds6_nbr_cache[];
00249 extern uip_ds6_route_t uip_ds6_routing_table[];
00250 #endif
00251
00252 static
00253 PT_THREAD(generate_routes(struct httpd_state *s))
00254 {
00255 uint8_t i=0;
00256 PSOCK_BEGIN(&s->sout);
00257
00258 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, TOP1);
00259 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, TOP2);
00260
00261 #if UIP_CONF_IPV6 //allow ip4 builds
00262 blen = 0;
00263 ADD("<h2>Neighbors [%u max]</h2>",UIP_DS6_NBR_NB);
00264 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00265 blen = 0;
00266 for(i = 0; i < UIP_DS6_NBR_NB; i++) {
00267 if(uip_ds6_nbr_cache[i].isused) {
00268 ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
00269 ADD("<br>");
00270
00271 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00272 blen = 0;
00273
00274 }
00275 }
00276
00277 ADD("<h2>Routes [%u max]</h2>",UIP_DS6_ROUTE_NB);
00278 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00279 blen = 0;
00280 for(i = 0; i < UIP_DS6_ROUTE_NB; i++) {
00281 if(uip_ds6_routing_table[i].isused) {
00282 ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
00283 ADD("/%u (via ", uip_ds6_routing_table[i].length);
00284 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00285 blen=0;
00286 ipaddr_add(&uip_ds6_routing_table[i].nexthop);
00287 if(uip_ds6_routing_table[i].state.lifetime < 600) {
00288 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00289 blen=0;
00290 ADD(") %lus<br>", uip_ds6_routing_table[i].state.lifetime);
00291 } else {
00292 ADD(")<br>");
00293 }
00294 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00295 blen = 0;
00296 }
00297 }
00298 if(blen > 0) {
00299 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00300 blen = 0;
00301 }
00302 #else
00303 blen = 0;i++;
00304 ADD("<h2>Hey, you got ip4 working!</h2>");
00305 PSOCK_GENERATOR_SEND(&s->sout, generate_string, buf);
00306 #endif
00307
00308 PSOCK_GENERATOR_SEND(&s->sout, generate_string_P, BOTTOM);
00309
00310 PSOCK_END(&s->sout);
00311 }
00312
00313
00314 httpd_simple_script_t
00315 httpd_simple_get_script(const char *name)
00316 {
00317 return generate_routes;
00318 }
00319
00320 char http_header_200[] PROGMEM = "HTTP/1.0 200 OK\r\nServer: Jackdaw\r\nConnection: close\r\n";
00321 char http_header_404[] PROGMEM = "HTTP/1.0 404 Not found\r\nServer: Jackdaw\r\nConnection: close\r\n";
00322 char NOT_FOUND[] PROGMEM = "<html><body bgcolor=\"white\"><center><h1>404 - file not found</h1></center></body></html>";
00323 static
00324 PT_THREAD(handle_output(struct httpd_state *s))
00325 {
00326 PT_BEGIN(&s->outputpt);
00327
00328 #if DEBUGLOGIC
00329 strcpy_P(s->filename,PSTR("/x"));
00330 #endif
00331 #if FIND_THE_SCRIPT
00332 s->script = httpd_simple_get_script(&s->filename[1]);
00333 if(s->script == NULL) {
00334 printf_P(PSTR("not found!"));
00335 strcpy_P(s->filename, PSTR("/notfound.html"));
00336
00337 PT_WAIT_THREAD(&s->outputpt,
00338 send_headers(s, http_header_404));
00339 PT_WAIT_THREAD(&s->outputpt,
00340 send_string_P(s, NOT_FOUND));
00341 uip_close();
00342
00343 PT_EXIT(&s->outputpt);
00344 } else {
00345 #else
00346 s->script = generate_routes;
00347 if (1) {
00348 #endif
00349
00350 PT_WAIT_THREAD(&s->outputpt,
00351 send_headers(s, http_header_200));
00352 PT_WAIT_THREAD(&s->outputpt, s->script(s));
00353 }
00354 s->script = NULL;
00355 PSOCK_CLOSE(&s->sout);
00356 PT_END(&s->outputpt);
00357 }
00358
00359 static void
00360 handle_connection(struct httpd_state *s)
00361 {
00362 #if DEBUGLOGIC
00363 handle_output(s);
00364 #else
00365 handle_input(s);
00366 if(s->state == STATE_OUTPUT) {
00367 handle_output(s);
00368 }
00369 #endif
00370 }
00371
00372 void
00373 httpd_appcall(void *state)
00374 {
00375 #if DEBUGLOGIC
00376 struct httpd_state *s;
00377 s = sg = (struct httpd_state *)memb_alloc(&conns);
00378 if (1) {
00379 #else
00380 struct httpd_state *s = (struct httpd_state *)state;
00381
00382 if(uip_closed() || uip_aborted() || uip_timedout()) {
00383 if(s != NULL) {
00384 s->script = NULL;
00385 memb_free(&conns, s);
00386 }
00387 } else if(uip_connected()) {
00388 s = (struct httpd_state *)memb_alloc(&conns);
00389 if(s == NULL) {
00390 uip_abort();
00391 webserver_log_file(&uip_conn->ripaddr, "reset (no memory block)");
00392 return;
00393 }
00394 #endif
00395 tcp_markconn(uip_conn, s);
00396 PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00397 PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, sizeof(s->inputbuf) - 1);
00398 PT_INIT(&s->outputpt);
00399 s->script = NULL;
00400 s->state = STATE_WAITING;
00401 timer_set(&s->timer, CLOCK_SECOND * 10);
00402 handle_connection(s);
00403 } else if(s != NULL) {
00404 if(uip_poll()) {
00405 if(timer_expired(&s->timer)) {
00406 uip_abort();
00407 s->script = NULL;
00408 memb_free(&conns, s);
00409 webserver_log_file(&uip_conn->ripaddr, "reset (timeout)");
00410 }
00411 } else {
00412 timer_restart(&s->timer);
00413 }
00414 handle_connection(s);
00415 } else {
00416 uip_abort();
00417 }
00418 }
00419
00420 PROCESS(httpd_process, "httpd");
00421 PROCESS_THREAD(httpd_process, ev, data)
00422 {
00423 PROCESS_BEGIN();
00424
00425 httpd_init();
00426
00427 while(1) {
00428 PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);
00429 httpd_appcall(data);
00430 }
00431
00432 PROCESS_END();
00433 }
00434