turn off debug printf in httpd
[clinton/Smoothieware.git] / src / libs / Network / uip / webserver / httpd.c
CommitLineData
d4ee6ee2
JM
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
29746399
SM
86#define GET 1
87#define POST 2
88#define OPTIONS 3
d4ee6ee2
JM
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
191227b5
JM
98//#define DEBUG_PRINTF printf
99#define DEBUG_PRINTF(...)
d4ee6ee2
JM
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
109static 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
135static 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
144static FILE *fd;
145static char *output_filename = NULL;
146static int file_cnt = 0;
147static 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
162static int close_file()
163{
164 free(output_filename);
165 output_filename = NULL;
166 fclose(fd);
167 return 1;
168}
169
170static int save_file(uint8_t *buf, unsigned int len)
171{
172 if (fwrite(buf, 1, len, fd) == len) {
173 file_cnt += len;
d4ee6ee2
JM
174 return 1;
175
176 } else {
177 close_file();
178 return 0;
179 }
180}
181
182static int fs_open(struct httpd_state *s)
183{
184 if (strncmp(s->filename, "/sd/", 4) == 0) {
185 DEBUG_PRINTF("Opening file %s\n", s->filename);
186 s->fd = fopen(s->filename, "r");
187 if (s->fd == NULL) {
188 DEBUG_PRINTF("Failed to open: %s\n", s->filename);
189 return 0;
190 }
191 return 1;
192
193 } else {
194 s->fd = NULL;
195 return httpd_fs_open(s->filename, &s->file);
196 }
197}
198
199/*---------------------------------------------------------------------------*/
200static PT_THREAD(send_command_response(struct httpd_state *s))
201{
202 PSOCK_BEGIN(&s->sout);
203
204 do {
205 PSOCK_WAIT_UNTIL( &s->sout, fifo_size(s->fifo) > 0 );
206 s->strbuf = fifo_pop(s->fifo);
207 if (s->strbuf != NULL) {
208 // send it
209 DEBUG_PRINTF("Sending response: %s", s->strbuf);
210 // TODO send as much as we can in one packet
211 PSOCK_SEND_STR(&s->sout, s->strbuf);
212 // free the strdup
213 free(s->strbuf);
214 }else if(--s->command_count <= 0) {
215 // when all commands have completed exit
216 break;
217 }
218 } while (1);
219
220 PSOCK_END(&s->sout);
221}
222
223/*---------------------------------------------------------------------------*/
224static unsigned short generate_part_of_file(void *state)
225{
226 struct httpd_state *s = (struct httpd_state *)state;
227
228 if (s->file.len > uip_mss()) {
229 s->len = uip_mss();
230 } else {
231 s->len = s->file.len;
232 }
233 memcpy(uip_appdata, s->file.data, s->len);
234
235 return s->len;
236}
237/*---------------------------------------------------------------------------*/
238static unsigned short generate_part_of_sd_file(void *state)
239{
240 struct httpd_state *s = (struct httpd_state *)state;
241
242 int len = fread(uip_appdata, 1, uip_mss(), s->fd);
243 if (len <= 0) {
244 // we need to send something
245 strcpy(uip_appdata, "\r\n");
246 len = 2;
247 s->len = 0;
248 } else {
249 s->len = len;
250 }
251 return len;
252}
253/*---------------------------------------------------------------------------*/
254static
255PT_THREAD(send_file(struct httpd_state *s))
256{
257 PSOCK_BEGIN(&s->sout);
258
259 do {
260 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_file, s);
261 s->file.len -= s->len;
262 s->file.data += s->len;
263 } while (s->file.len > 0);
264
265 PSOCK_END(&s->sout);
266}
267
268/*---------------------------------------------------------------------------*/
269static PT_THREAD(send_sd_file(struct httpd_state *s))
270{
271 PSOCK_BEGIN(&s->sout);
272
273 do {
274 PSOCK_GENERATOR_SEND(&s->sout, generate_part_of_sd_file, s);
275 } while (s->len > 0);
276
277 fclose(s->fd);
278 s->fd = NULL;
279
280 PSOCK_END(&s->sout);
281}
282
283/*---------------------------------------------------------------------------*/
284static PT_THREAD(send_headers_3(struct httpd_state *s, const char *statushdr, char send_content_type))
285{
286 char *ptr;
287
288 PSOCK_BEGIN(&s->sout);
289
290 PSOCK_SEND_STR(&s->sout, statushdr);
bc132e45 291 PSOCK_SEND_STR(&s->sout, http_header_all);
d4ee6ee2
JM
292
293 if (send_content_type) {
294 ptr = strrchr(s->filename, ISO_period);
295 if (ptr == NULL) {
296 PSOCK_SEND_STR(&s->sout, http_content_type_plain); // http_content_type_binary);
4075cc56 297 } else if (strncmp(http_html, ptr, 5) == 0) {
d4ee6ee2
JM
298 PSOCK_SEND_STR(&s->sout, http_content_type_html);
299 } else if (strncmp(http_css, ptr, 4) == 0) {
300 PSOCK_SEND_STR(&s->sout, http_content_type_css);
301 } else if (strncmp(http_png, ptr, 4) == 0) {
302 PSOCK_SEND_STR(&s->sout, http_content_type_png);
303 } else if (strncmp(http_gif, ptr, 4) == 0) {
304 PSOCK_SEND_STR(&s->sout, http_content_type_gif);
305 } else if (strncmp(http_jpg, ptr, 4) == 0) {
306 PSOCK_SEND_STR(&s->sout, http_content_type_jpg);
307 } else {
308 PSOCK_SEND_STR(&s->sout, http_content_type_plain);
309 }
310 }
311 PSOCK_END(&s->sout);
312}
313static PT_THREAD(send_headers(struct httpd_state *s, const char *statushdr))
314{
315 return send_headers_3(s, statushdr, 1);
316}
317/*---------------------------------------------------------------------------*/
318static
319PT_THREAD(handle_output(struct httpd_state *s))
320{
321 PT_BEGIN(&s->outputpt);
322
29746399
SM
323 if (s->method == OPTIONS) {
324 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_preflight));
325 PSOCK_SEND_STR(&s->sout, "OK\r\n");
326 }
327 else if (s->method == POST) {
d4ee6ee2
JM
328 if (strcmp(s->filename, "/command") == 0) {
329 DEBUG_PRINTF("Executed command post\n");
330 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
331 // send response as we get it
332 PT_WAIT_THREAD(&s->outputpt, send_command_response(s));
333
334 } else if (strcmp(s->filename, "/command_silent") == 0) {
335 DEBUG_PRINTF("Executed silent command post\n");
336 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
337
338 } else if (strcmp(s->filename, "/upload") == 0) {
339 DEBUG_PRINTF("upload output: %d\n", s->uploadok);
340 if (s->uploadok == 0) {
341 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_503));
342 PSOCK_SEND_STR(&s->sout, "FAILED\r\n");
343 } else {
344 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
345 PSOCK_SEND_STR(&s->sout, "OK\r\n");
346 }
347
348 } else {
349 DEBUG_PRINTF("Unknown POST: %s\n", s->filename);
350 httpd_fs_open(http_404_html, &s->file);
351 strcpy(s->filename, http_404_html);
352 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
353 PT_WAIT_THREAD(&s->outputpt, send_file(s));
354 }
355
356 } else {
357 // Presume method GET
358 if (!fs_open(s)) { // Note this has the side effect of opening the file
359 DEBUG_PRINTF("404 file not found\n");
360 httpd_fs_open(http_404_html, &s->file);
361 strcpy(s->filename, http_404_html);
362 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_404));
363 PT_WAIT_THREAD(&s->outputpt, send_file(s));
364
365 } else if (s->cache_page) {
366 if (s->fd != NULL) {
367 // if it was an sd file then we need to close it
368 fclose(s->fd);
369 s->fd = NULL;
370 }
371 // tell it it has not changed
372 DEBUG_PRINTF("304 Not Modified\n");
373 PT_WAIT_THREAD(&s->outputpt, send_headers_3(s, http_header_304, 0));
374
375 } else {
376 DEBUG_PRINTF("sending file %s\n", s->filename);
377 PT_WAIT_THREAD(&s->outputpt, send_headers(s, http_header_200));
378 if (s->fd != NULL) {
379 // send from sd card
380 PT_WAIT_THREAD(&s->outputpt, send_sd_file(s));
381
382 } else {
383 // send from FLASH
384 PT_WAIT_THREAD(&s->outputpt, send_file(s));
385 }
386 }
387 }
388
389 PSOCK_CLOSE(&s->sout);
390 PT_END(&s->outputpt);
391}
392
393/*---------------------------------------------------------------------------*/
394// this forces us to yield every other call as we read all data everytime
395static char has_newdata(struct httpd_state *s)
396{
397 if (s->upload_state == 1) {
398 /* All data in uip_appdata buffer already consumed. */
399 s->upload_state = 0;
400 return 0;
401 } else if (uip_newdata()) {
402 /* There is new data that has not been consumed. */
403 return 1;
404 } else {
405 /* There is no new data. */
406 return 0;
407 }
408}
409
410/*
93fe8efe 411 * handle the uploaded data, as there may be part of that buffer still in the last packet buffer
d4ee6ee2
JM
412 * write that first from the buf/len parameters
413 */
414static PT_THREAD(handle_uploaded_data(struct httpd_state *s, uint8_t *buf, int len))
415{
416 PT_BEGIN(&s->inputpt);
417
418 DEBUG_PRINTF("Uploading file: %s, %d\n", s->upload_name, s->content_length);
419
420 // The body is the raw data to be stored to the file
421 if (!open_file(s->upload_name)) {
422 DEBUG_PRINTF("failed to open file\n");
423 s->uploadok = 0;
424 PT_EXIT(&s->inputpt);
425 }
426
427 DEBUG_PRINTF("opened file: %s\n", s->upload_name);
428
429 if (len > 0) {
430 // write the first part of the buffer
431 if (!save_file(buf, len)) {
432 DEBUG_PRINTF("initial write failed\n");
433 s->uploadok = 0;
434 PT_EXIT(&s->inputpt);
435 }
436 s->content_length -= len;
437 }
438
439 s->upload_state = 1; // first time through we need to yield to get new data
440
441 // save the entire input buffer
442 while (s->content_length > 0) {
443 PT_WAIT_UNTIL(&s->inputpt, has_newdata(s));
444 s->upload_state = 1;
445
446 u8_t *readptr = (u8_t *)uip_appdata;
447 int readlen = uip_datalen();
448 //DEBUG_PRINTF("read %d bytes of data\n", readlen);
449
450 if (readlen > 0) {
451 if (!save_file(readptr, readlen)) {
452 DEBUG_PRINTF("write failed\n");
453 s->uploadok = 0;
454 PT_EXIT(&s->inputpt);
455 }
456 s->content_length -= readlen;
457 }
458 }
459
460 close_file();
461 s->uploadok = 1;
462 DEBUG_PRINTF("finished upload\n");
463
464 PT_END(&s->inputpt);
465}
466/*---------------------------------------------------------------------------*/
467static
468PT_THREAD(handle_input(struct httpd_state *s))
469{
470 PSOCK_BEGIN(&s->sin);
471
472 PSOCK_READTO(&s->sin, ISO_space);
473
29746399 474 if (strncmp(s->inputbuf, http_get, 3) == 0) {
d4ee6ee2
JM
475 s->method = GET;
476 } else if (strncmp(s->inputbuf, http_post, 4) == 0) {
477 s->method = POST;
29746399
SM
478 } else if (strncmp(s->inputbuf, http_options, 7) == 0) {
479 s->method = OPTIONS;
d4ee6ee2
JM
480 } else {
481 DEBUG_PRINTF("Unexpected method: %s\n", s->inputbuf);
482 PSOCK_CLOSE_EXIT(&s->sin);
483 }
484
29746399 485 DEBUG_PRINTF("Method: %s\n", s->method == POST ? "POST" : (s->method == GET ? "GET" : "OPTIONS"));
d4ee6ee2
JM
486
487 PSOCK_READTO(&s->sin, ISO_space);
488
489 if (s->inputbuf[0] != ISO_slash) {
490 PSOCK_CLOSE_EXIT(&s->sin);
491 }
492
493 if (s->inputbuf[1] == ISO_space) {
494 strncpy(s->filename, http_index_html, sizeof(s->filename));
495 } else {
496 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
497 strncpy(s->filename, &s->inputbuf[0], sizeof(s->filename));
498 }
499
500 DEBUG_PRINTF("filename: %s\n", s->filename);
501
502 /* httpd_log_file(uip_conn->ripaddr, s->filename);*/
503
504 s->state = STATE_HEADERS;
505 s->content_length = 0;
506 s->cache_page = 0;
507 while (1) {
508 if (s->state == STATE_HEADERS) {
509 // read the headers of the request
510 PSOCK_READTO(&s->sin, ISO_nl);
511 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
512 if (s->inputbuf[0] == '\r') {
513 DEBUG_PRINTF("end of headers\n");
29746399
SM
514 if (s->method == OPTIONS) {
515 s->state = STATE_OUTPUT;
516 break;
517 } else if (s->method == GET) {
d4ee6ee2
JM
518 s->state = STATE_OUTPUT;
519 break;
520 } else if (s->method == POST) {
521 if (strcmp(s->filename, "/upload") == 0) {
522 s->state = STATE_UPLOAD;
523 } else {
524 s->state = STATE_BODY;
525 }
526 }
527 } else {
528 DEBUG_PRINTF("reading header: %s\n", s->inputbuf);
529 // handle headers here
530 if (strncmp(s->inputbuf, http_content_length, sizeof(http_content_length) - 1) == 0) {
531 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
532 s->content_length = atoi(&s->inputbuf[sizeof(http_content_length) - 1]);
533 DEBUG_PRINTF("Content length= %s, %d\n", &s->inputbuf[sizeof(http_content_length) - 1], s->content_length);
534
535 } else if (strncmp(s->inputbuf, "X-Filename: ", 11) == 0) {
536 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
537 strncpy(s->upload_name, &s->inputbuf[12], sizeof(s->upload_name) - 1);
538 DEBUG_PRINTF("Upload name= %s\n", s->upload_name);
539
540 } else if (strncmp(s->inputbuf, http_cache_control, sizeof(http_cache_control) - 1) == 0) {
541 s->inputbuf[PSOCK_DATALEN(&s->sin) - 2] = 0;
542 s->cache_page = strncmp(http_no_cache, &s->inputbuf[sizeof(http_cache_control) - 1], sizeof(http_no_cache) - 1) != 0;
543 DEBUG_PRINTF("cache page= %d\n", s->cache_page);
544 }
545 }
546
547 } else if (s->state == STATE_BODY) {
548 if (s->method == POST && strcmp(s->filename, "/command") == 0) {
549 // create a callback stream and fifo for the results as it is a command
550 create_callback_stream(s);
551
552 } else if (s->method == POST && strcmp(s->filename, "/command_silent") == 0) {
553 // stick the command on the command queue specifying null output stream
554 s->pstream = NULL;
555
556 } else { // unknown POST
557 DEBUG_PRINTF("Unknown Post URL: %s\n", s->filename);
558 s->state = STATE_OUTPUT;
559 break;
560 }
561 s->command_count= 0;
562 // read the Body of the request, each line is a command
563 if (s->content_length > 0) {
564 DEBUG_PRINTF("start reading body %d...\n", s->content_length);
565 while (s->content_length > 2) {
566 PSOCK_READTO(&s->sin, ISO_nl);
567 s->inputbuf[PSOCK_DATALEN(&s->sin) - 1] = 0;
568 s->content_length -= PSOCK_DATALEN(&s->sin);
569 // stick the command on the command queue, with this connections stream output
570 DEBUG_PRINTF("Adding command: %s, left: %d\n", s->inputbuf, s->content_length);
571 network_add_command(s->inputbuf, s->pstream);
572 s->command_count++; // count number of command lines we submit
573 }
574 DEBUG_PRINTF("Read body done\n");
575 s->state = STATE_OUTPUT;
576
577 } else {
578 s->state = STATE_OUTPUT;
579 }
580 break;
581
582 } else if (s->state == STATE_UPLOAD) {
583 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)));
584 PSOCK_MARK_BUFFER_READ(&s->sin);
585 s->state = STATE_OUTPUT;
586 break;
587
588 } else {
589 DEBUG_PRINTF("WTF State: %d", s->state);
590 break;
591 }
592 }
593
594 PSOCK_END(&s->sin);
595}
596/*---------------------------------------------------------------------------*/
597static void
598handle_connection(struct httpd_state *s)
599{
600 if (s->state != STATE_OUTPUT) {
601 handle_input(s);
602 }
603 if (s->state == STATE_OUTPUT) {
604 handle_output(s);
605 }
606}
607/*---------------------------------------------------------------------------*/
608void
609httpd_appcall(void)
610{
611 struct httpd_state *s = (struct httpd_state *)(uip_conn->appstate);
612
613 if (uip_connected()) {
614 s = malloc(sizeof(struct httpd_state));
615 if (s == NULL) {
616 DEBUG_PRINTF("Connection: Out of memory\n");
617 uip_abort();
618 return;
619 }
620 uip_conn->appstate = s;
621 DEBUG_PRINTF("Connection: %d.%d.%d.%d:%d\n",
622 uip_ipaddr1(uip_conn->ripaddr), uip_ipaddr2(uip_conn->ripaddr),
623 uip_ipaddr3(uip_conn->ripaddr), uip_ipaddr4(uip_conn->ripaddr),
624 HTONS(uip_conn->rport));
625
626 PSOCK_INIT(&s->sin, s->inputbuf, sizeof(s->inputbuf) - 1);
627 PSOCK_INIT(&s->sout, s->inputbuf, sizeof(s->inputbuf) - 1);
628 PT_INIT(&s->outputpt);
629 PT_INIT(&s->inputpt);
630 s->state = STATE_WAITING;
631 /* timer_set(&s->timer, CLOCK_SECOND * 100);*/
632 s->timer = 0;
633 s->fd = NULL;
634 s->strbuf = NULL;
635 s->fifo = NULL;
636 s->pstream = NULL;
637 }
638
639 if (s == NULL) {
640 DEBUG_PRINTF("ERROR no state context: %d\n", uip_flags);
641 uip_abort();
642 return;
643 }
644
645 // check for timeout on connection here so we can cleanup if we abort
646 if (uip_poll()) {
647 ++s->timer;
648 if (s->timer >= 20 * 2) { // we have a 0.5 second poll and we want 20 second timeout
649 DEBUG_PRINTF("Timer expired, aborting\n");
650 uip_abort();
651 }
652 } else {
653 s->timer = 0;
654 }
655
656 if (uip_closed() || uip_aborted() || uip_timedout()) {
657 DEBUG_PRINTF("Closing connection: %d\n", HTONS(uip_conn->rport));
658 if (s->fd != NULL) fclose(fd); // clean up
659 if (s->strbuf != NULL) free(s->strbuf);
660 if (s->pstream != NULL) {
661 // free these if they were allocated
662 delete_fifo(s->fifo);
663 delete_callback_stream(s->pstream); // this will mark it as closed and will get deleted when no longer needed
664 }
665 free(s) ;
666 uip_conn->appstate = NULL;
667
668 } else {
669 handle_connection(s);
670 }
671}
672
673/*---------------------------------------------------------------------------*/
674/**
675 * \brief Initialize the web server
676 *
677 * This function initializes the web server and should be
678 * called at system boot-up.
679 */
680void httpd_init(void)
681{
682 uip_listen(HTONS(80));
683}
684/*---------------------------------------------------------------------------*/
685/** @} */