merged edge into feature/spindle-refactor branch
[clinton/Smoothieware.git] / src / libs / Network / uip / webserver / httpd.c
1 #pragma GCC diagnostic ignored "-Wredundant-decls"
2 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
3 #pragma GCC diagnostic ignored "-Wcast-align"
4 #pragma GCC diagnostic ignored "-Wcast-qual"
5 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
6
7 /**
8 * \addtogroup apps
9 * @{
10 */
11
12 /**
13 * \defgroup httpd Web server
14 * @{
15 * The uIP web server is a very simplistic implementation of an HTTP
16 * server. It can serve web pages and files from a read-only ROM
17 * filesystem, and provides a very small scripting language.
18
19 */
20
21 /**
22 * \file
23 * Web server
24 * \author
25 * Adam Dunkels <adam@sics.se>
26 */
27
28
29 /*
30 * Copyright (c) 2004, Adam Dunkels.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the Institute nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * This file is part of the uIP TCP/IP stack.
58 *
59 * Author: Adam Dunkels <adam@sics.se>
60 *
61 * $Id: httpd.c,v 1.2 2006/06/11 21:46:38 adam Exp $
62 */
63
64 #include <stdio.h>
65
66 #include "uip.h"
67 #include "httpd.h"
68 #include "httpd-fs.h"
69 #include "http-strings.h"
70
71 #include <string.h>
72 #include "stdio.h"
73 #include "stdlib.h"
74
75 #include "CommandQueue.h"
76 #include "CallbackStream.h"
77
78 #include "c-fifo.h"
79
80 #define STATE_WAITING 0
81 #define STATE_HEADERS 1
82 #define STATE_BODY 2
83 #define STATE_OUTPUT 3
84 #define STATE_UPLOAD 4
85
86 #define GET 1
87 #define POST 2
88 #define OPTIONS 3
89
90 #define ISO_nl 0x0a
91 #define ISO_space 0x20
92 #define ISO_bang 0x21
93 #define ISO_percent 0x25
94 #define ISO_period 0x2e
95 #define ISO_slash 0x2f
96 #define ISO_colon 0x3a
97
98 #define DEBUG_PRINTF printf
99 //#define DEBUG_PRINTF(...)
100
101
102 // this callback gets the results of a command, line by line. need to check if
103 // we need to stall the upstream sender return 0 if stalled 1 if ok to keep
104 // providing more -1 if the connection has closed or is not in output state.
105 // need to see which connection to send to based on state and add result to
106 // that fifo for each connection. NOTE this will not get called if the
107 // connection has been closed and the stream will get deleted when the last
108 // command has been executed
109 static int command_result(const char *str, void *state)
110 {
111 struct httpd_state *s = (struct httpd_state *)state;
112 if (s == NULL) {
113 // connection was closed so discard, this should never happen
114 DEBUG_PRINTF("ERROR: command result for closed state %d\n", (int)state);
115 return -1;
116 }
117
118 if (str == NULL) {
119 DEBUG_PRINTF("End of command (%p)\n", state);
120 fifo_push(s->fifo, NULL);
121
122 } else {
123 if (fifo_size(s->fifo) < 10) {
124 DEBUG_PRINTF("Got command result (%p): %s", state, str);
125 fifo_push(s->fifo, strdup(str));
126 return 1;
127 } else {
128 DEBUG_PRINTF("command result fifo is full (%p)\n", state);
129 return 0;
130 }
131 }
132 return 1;
133 }
134
135 static void create_callback_stream(struct httpd_state *s)
136 {
137 // need to create a callback stream here, but do one per connection pass
138 // the state to the callback, also create the fifo for the command results
139 s->fifo = new_fifo();
140 s->pstream = new_callback_stream(command_result, s);
141 }
142
143 // Used to save files to SDCARD during upload
144 static FILE *fd;
145 static char *output_filename = NULL;
146 static int file_cnt = 0;
147 static int open_file(const char *fn)
148 {
149 if (output_filename != NULL) free(output_filename);
150 output_filename = malloc(strlen(fn) + 5);
151 strcpy(output_filename, "/sd/");
152 strcat(output_filename, fn);
153 fd = fopen(output_filename, "w");
154 if (fd == NULL) {
155 free(output_filename);
156 output_filename = NULL;
157 return 0;
158 }
159 return 1;
160 }
161
162 static int close_file()
163 {
164 free(output_filename);
165 output_filename = NULL;
166 fclose(fd);
167 return 1;
168 }
169
170 static int save_file(uint8_t *buf, unsigned int len)
171 {
172 if (fwrite(buf, 1, len, fd) == len) {
173 file_cnt += len;
174 // HACK alert work around bug causing file corruption when writing large amounts of data
175 if (file_cnt >= 400) {
176 file_cnt = 0;
177 fclose(fd);
178 fd = fopen(output_filename, "a");
179 }
180 return 1;
181
182 } else {
183 close_file();
184 return 0;
185 }
186 }
187
188 static int fs_open(struct httpd_state *s)
189 {
190 if (strncmp(s->filename, "/sd/", 4) == 0) {
191 DEBUG_PRINTF("Opening file %s\n", s->filename);
192 s->fd = fopen(s->filename, "r");
193 if (s->fd == NULL) {
194 DEBUG_PRINTF("Failed to open: %s\n", s->filename);
195 return 0;
196 }
197 return 1;
198
199 } else {
200 s->fd = NULL;
201 return httpd_fs_open(s->filename, &s->file);
202 }
203 }
204
205 /*---------------------------------------------------------------------------*/
206 static PT_THREAD(send_command_response(struct httpd_state *s))
207 {
208 PSOCK_BEGIN(&s->sout);
209
210 do {
211 PSOCK_WAIT_UNTIL( &s->sout, fifo_size(s->fifo) > 0 );
212 s->strbuf = fifo_pop(s->fifo);
213 if (s->strbuf != NULL) {
214 // send it
215 DEBUG_PRINTF("Sending response: %s", s->strbuf);
216 // TODO send as much as we can in one packet
217 PSOCK_SEND_STR(&s->sout, s->strbuf);
218 // free the strdup
219 free(s->strbuf);
220 }else if(--s->command_count <= 0) {
221 // when all commands have completed exit
222 break;
223 }
224 } while (1);
225
226 PSOCK_END(&s->sout);
227 }
228
229 /*---------------------------------------------------------------------------*/
230 static unsigned short generate_part_of_file(void *state)
231 {
232 struct httpd_state *s = (struct httpd_state *)state;
233
234 if (s->file.len > uip_mss()) {
235 s->len = uip_mss();
236 } else {
237 s->len = s->file.len;
238 }
239 memcpy(uip_appdata, s->file.data, s->len);
240
241 return s->len;
242 }
243 /*---------------------------------------------------------------------------*/
244 static unsigned short generate_part_of_sd_file(void *state)
245 {
246 struct httpd_state *s = (struct httpd_state *)state;
247
248 int len = fread(uip_appdata, 1, uip_mss(), s->fd);
249 if (len <= 0) {
250 // we need to send something
251 strcpy(uip_appdata, "\r\n");
252 len = 2;
253 s->len = 0;
254 } else {
255 s->len = len;
256 }
257 return len;
258 }
259 /*---------------------------------------------------------------------------*/
260 static
261 PT_THREAD(send_file(struct httpd_state *s))
262 {
263 PSOCK_BEGIN(&s->sout);
264
265 do {
266 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
267 s->file.len -= s->len;
268 s->file.data += s->len;
269 } while (s->file.len > 0);
270
271 PSOCK_END(&s->sout);
272 }
273
274 /*---------------------------------------------------------------------------*/
275 static PT_THREAD(send_sd_file(struct httpd_state *s))
276 {
277 PSOCK_BEGIN(&s->sout);
278
279 do {
280 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_sd_file, s);
281 } while (s->len > 0);
282
283 fclose(s->fd);
284 s->fd = NULL;
285
286 PSOCK_END(&s->sout);
287 }
288
289 /*---------------------------------------------------------------------------*/
290 static PT_THREAD(send_headers_3(struct httpd_state *s, const char *statushdr, char send_content_type))
291 {
292 char *ptr;
293
294 PSOCK_BEGIN(&s->sout);
295
296 PSOCK_SEND_STR(&s->sout, statushdr);
297 PSOCK_SEND_STR(&s->sout, http_header_all);
298
299 if (send_content_type) {
300 ptr = strrchr(s->filename, ISO_period);
301 if (ptr == NULL) {
302 PSOCK_SEND_STR(&s->sout, http_content_type_plain); // http_content_type_binary);
303 } else if (strncmp(http_html, ptr, 5) == 0) {
304 PSOCK_SEND_STR(&s->sout, http_content_type_html);
305 } else if (strncmp(http_css, ptr, 4) == 0) {
306 PSOCK_SEND_STR(&s->sout, http_content_type_css);
307 } else if (strncmp(http_png, ptr, 4) == 0) {
308 PSOCK_SEND_STR(&s->sout, http_content_type_png);
309 } else if (strncmp(http_gif, ptr, 4) == 0) {
310 PSOCK_SEND_STR(&s->sout, http_content_type_gif);
311 } else if (strncmp(http_jpg, ptr, 4) == 0) {
312 PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
313 } else {
314 PSOCK_SEND_STR(&s->sout, http_content_type_plain);
315 }
316 }
317 PSOCK_END(&s->sout);
318 }
319 static PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
320 {
321 return send_headers_3(s, statushdr, 1);
322 }
323 /*---------------------------------------------------------------------------*/
324 static
325 PT_THREAD(handle_output(struct httpd_state *s))
326 {
327 PT_BEGIN(&s->outputpt);
328
329 if (s->method == OPTIONS) {
330 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_preflight));
331 PSOCK_SEND_STR(&s->sout, "OK\r\n");
332 }
333 else if (s->method == POST) {
334 if (strcmp(s->filename, "/command") == 0) {
335 DEBUG_PRINTF("Executed command post\n");
336 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
337 // send response as we get it
338 PT_WAIT_THREAD(&s->outputpt, send_command_response(s));
339
340 } else if (strcmp(s->filename, "/command_silent") == 0) {
341 DEBUG_PRINTF("Executed silent command post\n");
342 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
343
344 } else if (strcmp(s->filename, "/upload") == 0) {
345 DEBUG_PRINTF("upload output: %d\n", s->uploadok);
346 if (s->uploadok == 0) {
347 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_503));
348 PSOCK_SEND_STR(&s->sout, "FAILED\r\n");
349 } else {
350 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
351 PSOCK_SEND_STR(&s->sout, "OK\r\n");
352 }
353
354 } else {
355 DEBUG_PRINTF("Unknown POST: %s\n", s->filename);
356 httpd_fs_open(http_404_html, &s->file);
357 strcpy(s->filename, http_404_html);
358 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
359 PT_WAIT_THREAD(&s->outputpt, send_file(s));
360 }
361
362 } else {
363 // Presume method GET
364 if (!fs_open(s)) { // Note this has the side effect of opening the file
365 DEBUG_PRINTF("404 file not found\n");
366 httpd_fs_open(http_404_html, &s->file);
367 strcpy(s->filename, http_404_html);
368 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
369 PT_WAIT_THREAD(&s->outputpt, send_file(s));
370
371 } else if (s->cache_page) {
372 if (s->fd != NULL) {
373 // if it was an sd file then we need to close it
374 fclose(s->fd);
375 s->fd = NULL;
376 }
377 // tell it it has not changed
378 DEBUG_PRINTF("304 Not Modified\n");
379 PT_WAIT_THREAD(&s->outputpt, send_headers_3(s, http_header_304, 0));
380
381 } else {
382 DEBUG_PRINTF("sending file %s\n", s->filename);
383 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
384 if (s->fd != NULL) {
385 // send from sd card
386 PT_WAIT_THREAD(&s->outputpt, send_sd_file(s));
387
388 } else {
389 // send from FLASH
390 PT_WAIT_THREAD(&s->outputpt, send_file(s));
391 }
392 }
393 }
394
395 PSOCK_CLOSE(&s->sout);
396 PT_END(&s->outputpt);
397 }
398
399 /*---------------------------------------------------------------------------*/
400 // this forces us to yield every other call as we read all data everytime
401 static char has_newdata(struct httpd_state *s)
402 {
403 if (s->upload_state == 1) {
404 /* All data in uip_appdata buffer already consumed. */
405 s->upload_state = 0;
406 return 0;
407 } else if (uip_newdata()) {
408 /* There is new data that has not been consumed. */
409 return 1;
410 } else {
411 /* There is no new data. */
412 return 0;
413 }
414 }
415
416 /*
417 * handle the uploaded data, as there may be part of that buffer still in the last packet buffer
418 * write that first from the buf/len parameters
419 */
420 static PT_THREAD(handle_uploaded_data(struct httpd_state *s, uint8_t *buf, int len))
421 {
422 PT_BEGIN(&s->inputpt);
423
424 DEBUG_PRINTF("Uploading file: %s, %d\n", s->upload_name, s->content_length);
425
426 // The body is the raw data to be stored to the file
427 if (!open_file(s->upload_name)) {
428 DEBUG_PRINTF("failed to open file\n");
429 s->uploadok = 0;
430 PT_EXIT(&s->inputpt);
431 }
432
433 DEBUG_PRINTF("opened file: %s\n", s->upload_name);
434
435 if (len > 0) {
436 // write the first part of the buffer
437 if (!save_file(buf, len)) {
438 DEBUG_PRINTF("initial write failed\n");
439 s->uploadok = 0;
440 PT_EXIT(&s->inputpt);
441 }
442 s->content_length -= len;
443 }
444
445 s->upload_state = 1; // first time through we need to yield to get new data
446
447 // save the entire input buffer
448 while (s->content_length > 0) {
449 PT_WAIT_UNTIL(&s->inputpt, has_newdata(s));
450 s->upload_state = 1;
451
452 u8_t *readptr = (u8_t *)uip_appdata;
453 int readlen = uip_datalen();
454 //DEBUG_PRINTF("read %d bytes of data\n", readlen);
455
456 if (readlen > 0) {
457 if (!save_file(readptr, readlen)) {
458 DEBUG_PRINTF("write failed\n");
459 s->uploadok = 0;
460 PT_EXIT(&s->inputpt);
461 }
462 s->content_length -= readlen;
463 }
464 }
465
466 close_file();
467 s->uploadok = 1;
468 DEBUG_PRINTF("finished upload\n");
469
470 PT_END(&s->inputpt);
471 }
472 /*---------------------------------------------------------------------------*/
473 static
474 PT_THREAD(handle_input(struct httpd_state *s))
475 {
476 PSOCK_BEGIN(&s->sin);
477
478 PSOCK_READTO(&s->sin, ISO_space);
479
480 if (strncmp(s->inputbuf, http_get, 3) == 0) {
481 s->method = GET;
482 } else if (strncmp(s->inputbuf, http_post, 4) == 0) {
483 s->method = POST;
484 } else if (strncmp(s->inputbuf, http_options, 7) == 0) {
485 s->method = OPTIONS;
486 } else {
487 DEBUG_PRINTF("Unexpected method: %s\n", s->inputbuf);
488 PSOCK_CLOSE_EXIT(&s->sin);
489 }
490
491 DEBUG_PRINTF("Method: %s\n", s->method == POST ? "POST" : (s->method == GET ? "GET" : "OPTIONS"));
492
493 PSOCK_READTO(&s->sin, ISO_space);
494
495 if (s->inputbuf[0] != ISO_slash) {
496 PSOCK_CLOSE_EXIT(&s->sin);
497 }
498
499 if (s->inputbuf[1] == ISO_space) {
500 strncpy(s->filename, http_index_html, sizeof(s->filename));
501 } else {
502 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
503 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
504 }
505
506 DEBUG_PRINTF("filename: %s\n", s->filename);
507
508 /* httpd_log_file(uip_conn->ripaddr, s->filename);*/
509
510 s->state = STATE_HEADERS;
511 s->content_length = 0;
512 s->cache_page = 0;
513 while (1) {
514 if (s->state == STATE_HEADERS) {
515 // read the headers of the request
516 PSOCK_READTO(&s->sin, ISO_nl);
517 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
518 if (s->inputbuf[0] == '\r') {
519 DEBUG_PRINTF("end of headers\n");
520 if (s->method == OPTIONS) {
521 s->state = STATE_OUTPUT;
522 break;
523 } else if (s->method == GET) {
524 s->state = STATE_OUTPUT;
525 break;
526 } else if (s->method == POST) {
527 if (strcmp(s->filename, "/upload") == 0) {
528 s->state = STATE_UPLOAD;
529 } else {
530 s->state = STATE_BODY;
531 }
532 }
533 } else {
534 DEBUG_PRINTF("reading header: %s\n", s->inputbuf);
535 // handle headers here
536 if (strncmp(s->inputbuf, http_content_length, sizeof(http_content_length) - 1) == 0) {
537 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
538 s->content_length = atoi(&s->inputbuf[sizeof(http_content_length) - 1]);
539 DEBUG_PRINTF("Content length= %s, %d\n", &s->inputbuf[sizeof(http_content_length) - 1], s->content_length);
540
541 } else if (strncmp(s->inputbuf, "X-Filename: ", 11) == 0) {
542 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
543 strncpy(s->upload_name, &s->inputbuf[12], sizeof(s->upload_name) - 1);
544 DEBUG_PRINTF("Upload name= %s\n", s->upload_name);
545
546 } else if (strncmp(s->inputbuf, http_cache_control, sizeof(http_cache_control) - 1) == 0) {
547 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
548 s->cache_page = strncmp(http_no_cache, &s->inputbuf[sizeof(http_cache_control) - 1], sizeof(http_no_cache) - 1) != 0;
549 DEBUG_PRINTF("cache page= %d\n", s->cache_page);
550 }
551 }
552
553 } else if (s->state == STATE_BODY) {
554 if (s->method == POST && strcmp(s->filename, "/command") == 0) {
555 // create a callback stream and fifo for the results as it is a command
556 create_callback_stream(s);
557
558 } else if (s->method == POST && strcmp(s->filename, "/command_silent") == 0) {
559 // stick the command on the command queue specifying null output stream
560 s->pstream = NULL;
561
562 } else { // unknown POST
563 DEBUG_PRINTF("Unknown Post URL: %s\n", s->filename);
564 s->state = STATE_OUTPUT;
565 break;
566 }
567 s->command_count= 0;
568 // read the Body of the request, each line is a command
569 if (s->content_length > 0) {
570 DEBUG_PRINTF("start reading body %d...\n", s->content_length);
571 while (s->content_length > 2) {
572 PSOCK_READTO(&s->sin, ISO_nl);
573 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
574 s->content_length -= PSOCK_DATALEN(&s->sin);
575 // stick the command on the command queue, with this connections stream output
576 DEBUG_PRINTF("Adding command: %s, left: %d\n", s->inputbuf, s->content_length);
577 network_add_command(s->inputbuf, s->pstream);
578 s->command_count++; // count number of command lines we submit
579 }
580 DEBUG_PRINTF("Read body done\n");
581 s->state = STATE_OUTPUT;
582
583 } else {
584 s->state = STATE_OUTPUT;
585 }
586 break;
587
588 } else if (s->state == STATE_UPLOAD) {
589 PSOCK_WAIT_THREAD(&s->sin, handle_uploaded_data(s, PSOCK_GET_START_OF_REST_OF_BUFFER(&s->sin), PSOCK_GET_LENGTH_OF_REST_OF_BUFFER(&s->sin)));
590 PSOCK_MARK_BUFFER_READ(&s->sin);
591 s->state = STATE_OUTPUT;
592 break;
593
594 } else {
595 DEBUG_PRINTF("WTF State: %d", s->state);
596 break;
597 }
598 }
599
600 PSOCK_END(&s->sin);
601 }
602 /*---------------------------------------------------------------------------*/
603 static void
604 handle_connection(struct httpd_state *s)
605 {
606 if (s->state != STATE_OUTPUT) {
607 handle_input(s);
608 }
609 if (s->state == STATE_OUTPUT) {
610 handle_output(s);
611 }
612 }
613 /*---------------------------------------------------------------------------*/
614 void
615 httpd_appcall(void)
616 {
617 struct httpd_state *s = (struct httpd_state *)(uip_conn->appstate);
618
619 if (uip_connected()) {
620 s = malloc(sizeof(struct httpd_state));
621 if (s == NULL) {
622 DEBUG_PRINTF("Connection: Out of memory\n");
623 uip_abort();
624 return;
625 }
626 uip_conn->appstate = s;
627 DEBUG_PRINTF("Connection: %d.%d.%d.%d:%d\n",
628 uip_ipaddr1(uip_conn->ripaddr), uip_ipaddr2(uip_conn->ripaddr),
629 uip_ipaddr3(uip_conn->ripaddr), uip_ipaddr4(uip_conn->ripaddr),
630 HTONS(uip_conn->rport));
631
632 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
633 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
634 PT_INIT(&s->outputpt);
635 PT_INIT(&s->inputpt);
636 s->state = STATE_WAITING;
637 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
638 s->timer = 0;
639 s->fd = NULL;
640 s->strbuf = NULL;
641 s->fifo = NULL;
642 s->pstream = NULL;
643 }
644
645 if (s == NULL) {
646 DEBUG_PRINTF("ERROR no state context: %d\n", uip_flags);
647 uip_abort();
648 return;
649 }
650
651 // check for timeout on connection here so we can cleanup if we abort
652 if (uip_poll()) {
653 ++s->timer;
654 if (s->timer >= 20 * 2) { // we have a 0.5 second poll and we want 20 second timeout
655 DEBUG_PRINTF("Timer expired, aborting\n");
656 uip_abort();
657 }
658 } else {
659 s->timer = 0;
660 }
661
662 if (uip_closed() || uip_aborted() || uip_timedout()) {
663 DEBUG_PRINTF("Closing connection: %d\n", HTONS(uip_conn->rport));
664 if (s->fd != NULL) fclose(fd); // clean up
665 if (s->strbuf != NULL) free(s->strbuf);
666 if (s->pstream != NULL) {
667 // free these if they were allocated
668 delete_fifo(s->fifo);
669 delete_callback_stream(s->pstream); // this will mark it as closed and will get deleted when no longer needed
670 }
671 free(s) ;
672 uip_conn->appstate = NULL;
673
674 } else {
675 handle_connection(s);
676 }
677 }
678
679 /*---------------------------------------------------------------------------*/
680 /**
681 * \brief Initialize the web server
682 *
683 * This function initializes the web server and should be
684 * called at system boot-up.
685 */
686 void httpd_init(void)
687 {
688 uip_listen(HTONS(80));
689 }
690 /*---------------------------------------------------------------------------*/
691 /** @} */