45 #include "contiki-net.h" 
   50 #define PRINTF(...) printf(__VA_ARGS__) 
   55 #ifndef WEBSERVER_CONF_CFS_CONNS 
   56 #define CONNS UIP_CONNS 
   58 #define CONNS WEBSERVER_CONF_CFS_CONNS 
   61 #ifndef WEBSERVER_CONF_CFS_URLCONV 
   64 #define URLCONV WEBSERVER_CONF_CFS_URLCONV 
   71 static struct httpd_ws_state conns[CONNS];
 
   73 PROCESS(httpd_ws_process, 
"Web server (WS)");
 
   76 #define ISO_space   0x20 
   77 #define ISO_period  0x2e 
   78 #define ISO_slash   0x2f 
   80 uint16_t http_connections = 0;
 
   82 static const char http_10[] = 
" HTTP/1.0\r\n";
 
   83 static const char http_content_type[] = 
"Content-Type:";
 
   84 static const char http_content_type_html[] = 
"text/html";
 
   85 static const char http_content_len[] = 
"Content-Length:";
 
   86 static const char http_header_404[] =
 
   87   "HTTP/1.0 404 Not found\r\nServer: Contiki\r\nConnection: close\r\n";
 
   88 static const char http_header_200[] =
 
   89   "HTTP/1.0 200 OK\r\nServer: Contiki\r\nConnection: close\r\n";
 
   90 static const char html_not_found[] =
 
   91   "<html><body><h1>Page not found</h1></body></html>";
 
   95 httpd_state_init(
void)
 
   99   for(i = 0; i < CONNS; i++) {
 
  100     conns[i].state = HTTPD_WS_STATE_UNUSED;
 
  104 static struct httpd_ws_state *
 
  105 httpd_state_alloc(
void)
 
  109   for(i = 0; i < CONNS; i++) {
 
  110     if(conns[i].state == HTTPD_WS_STATE_UNUSED) {
 
  111       conns[i].state = HTTPD_WS_STATE_INPUT;
 
  118 #define httpd_state_free(s) (s->state = HTTPD_WS_STATE_UNUSED) 
  121 PT_THREAD(send_string(
struct httpd_ws_state *s, 
const char *str, uint16_t len))
 
  125   SEND_STRING(&s->sout, str, len);
 
  131 PT_THREAD(send_headers(
struct httpd_ws_state *s, 
const char *statushdr))
 
  135   SEND_STRING(&s->sout, statushdr, strlen(statushdr));
 
  136   s->outbuf_pos = snprintf(s->outbuf, 
sizeof(s->outbuf),
 
  137                            "%s %s\r\n\r\n", http_content_type,
 
  138                            s->content_type == 
NULL 
  139                            ? http_content_type_html : s->content_type);
 
  140   SEND_STRING(&s->sout, s->outbuf, s->outbuf_pos);
 
  147 PT_THREAD(handle_output(
struct httpd_ws_state *s))
 
  151   s->content_type = http_content_type_html;
 
  152   s->script = httpd_ws_get_script(s);
 
  153   if(s->script == 
NULL) {
 
  156                    send_string(s, html_not_found, strlen(html_not_found)));
 
  161     if(s->request_type == HTTPD_WS_POST) {
 
  163       s->state = HTTPD_WS_STATE_INPUT;
 
  164       PT_WAIT_UNTIL(&s->outputpt, s->state == HTTPD_WS_STATE_OUTPUT);
 
  175 PT_THREAD(handle_request(
struct httpd_ws_state *s))
 
  181                  send_string(s, s->filename, strlen(s->filename)));
 
  183   if(s->outbuf_pos > 0) {
 
  184     PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
 
  187   if(s->content_type != 
NULL) {
 
  188     s->outbuf_pos = snprintf(s->outbuf, 
sizeof(s->outbuf), 
"%s %s\r\n",
 
  189                              http_content_type, s->content_type);
 
  190     PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
 
  193   if(s->output_extra_headers != 
NULL) {
 
  194     s->response_index = 0;
 
  195     while((s->outbuf_pos =
 
  196            s->output_extra_headers(s,
 
  197                                    s->outbuf, 
sizeof(s->outbuf),
 
  198                                    s->response_index)) > 0) {
 
  199       PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
 
  205   if(s->content_len > 0) {
 
  206     s->outbuf_pos = snprintf(s->outbuf, 
sizeof(s->outbuf), 
"%s %u\r\n",
 
  207                              http_content_len, s->content_len);
 
  210   if(s->outbuf_pos + 2 < 
sizeof(s->outbuf)) {
 
  211     s->outbuf[s->outbuf_pos++] = 
'\r';
 
  212     s->outbuf[s->outbuf_pos++] = 
'\n';
 
  214   PT_WAIT_THREAD(&s->outputpt, send_string(s, s->outbuf, s->outbuf_pos));
 
  217   if(s->script != 
NULL) {
 
  220   s->state = HTTPD_WS_STATE_REQUEST_INPUT;
 
  227 PT_THREAD(handle_input(
struct httpd_ws_state *s))
 
  232   if(strncmp(s->inputbuf, 
"GET ", 4) == 0) {
 
  233     s->request_type = HTTPD_WS_GET;
 
  234   } 
else if(strncmp(s->inputbuf, 
"POST ", 5) == 0) {
 
  235     s->request_type = HTTPD_WS_POST;
 
  237   } 
else if(strncmp(s->inputbuf, 
"HTTP ", 5) == 0) {
 
  238     s->request_type = HTTPD_WS_RESPONSE;
 
  246   if(s->inputbuf[0] != ISO_slash) {
 
  252   urlconv_tofilename(s->filename, s->inputbuf, 
sizeof(s->filename));
 
  255   snprintf(s->filename, 
sizeof(s->filename), 
"%s", s->inputbuf);
 
  259   s->state = HTTPD_WS_STATE_OUTPUT;
 
  264     if(s->request_type == HTTPD_WS_POST &&
 
  265        strncmp(s->inputbuf, http_content_len, 15) == 0) {
 
  267       s->content_len = atoi(&s->inputbuf[16]);
 
  274     } 
else if(s->request_type == HTTPD_WS_POST) {
 
  278       s->state = HTTPD_WS_STATE_OUTPUT;
 
  285 handle_connection(
struct httpd_ws_state *s)
 
  287   if(s->state == HTTPD_WS_STATE_REQUEST_OUTPUT) {
 
  291   if(s->state == HTTPD_WS_STATE_OUTPUT) {
 
  297 httpd_ws_appcall(
void *state)
 
  299   struct httpd_ws_state *s = (
struct httpd_ws_state *)state;
 
  303       PRINTF(
"HTTPD-WS: closed/aborted (%d)\n", http_connections);
 
  307       PRINTF(
"HTTPD-WS: closed/aborted ** NO HTTPD_WS_STATE!!! ** (%d)\n",
 
  312       s = httpd_state_alloc();
 
  315         PRINTF(
"HTTPD-WS: aborting - no resource (%d)\n", http_connections);
 
  322       s->state = HTTPD_WS_STATE_INPUT;
 
  325       s->state = HTTPD_WS_STATE_REQUEST_OUTPUT;
 
  327     PSOCK_INIT(&s->sin, (uint8_t *)s->inputbuf, 
sizeof(s->inputbuf) - 1);
 
  328     PSOCK_INIT(&s->sout, (uint8_t *)s->inputbuf, 
sizeof(s->inputbuf) - 1);
 
  331     handle_connection(s);
 
  332   } 
else if(s != 
NULL) {
 
  336         PRINTF(
"HTTPD-WS: aborting - http timeout (%d)\n", http_connections);
 
  341         PRINTF(
"HTTPD-WS: uip-poll (%d)\n", http_connections);
 
  348     handle_connection(s);
 
  350     PRINTF(
"HTTPD-WS: aborting - no state (%d)\n", http_connections);
 
  365 struct httpd_ws_state *
 
  366 httpd_ws_request(
char request_type, 
const char *host_ip, 
const char *host_hdr,
 
  367                  uint16_t port, 
const char *file,
 
  368                  const char *content_type, uint16_t content_len,
 
  369                  httpd_ws_script_t generator)
 
  371   struct httpd_ws_state *s;
 
  373   uip_ipaddr_t *ipaddr;
 
  389   s = httpd_state_alloc();
 
  396   switch(request_type) {
 
  398     request_str = 
"POST ";
 
  401     request_str = 
"PUT ";
 
  404     request_str = 
"GET ";
 
  408   s->request_type = request_type;
 
  409   s->content_len = content_len;
 
  410   s->content_type = content_type;
 
  411   s->script = generator;
 
  412   s->state = HTTPD_WS_STATE_REQUEST_OUTPUT;
 
  416   snprintf(s->filename, 
sizeof(s->filename), 
"%s%s%s",
 
  417            request_str, file, http_10);
 
  418   s->outbuf_pos = snprintf(s->outbuf, 
sizeof(s->outbuf), 
"Host:%s\r\n",
 
  419                            host_hdr != 
NULL ? host_hdr : host_ip);
 
  425     PRINTF(
"HTTPD-WS: aborting... could not allocate tcp connection (%d)\n",
 
  431   PRINTF(
"HTTPD-WS: created http connection (%d)\n", http_connections);
 
  445   PRINTF(
"Buffer size, input %d, output\n",
 
  446          HTTPD_INBUF_SIZE, HTTPD_OUTBUF_SIZE);
 
  457       httpd_ws_appcall(data);
 
  459       PRINTF(
"HTTPD States: ");
 
  460       for(i = 0; i < CONNS; i++) {
 
  461         PRINTF(
"%d ", conns[i].state);
 
  462         if(conns[i].state != HTTPD_WS_STATE_UNUSED &&
 
  464           conns[i].state = HTTPD_WS_STATE_UNUSED;
 
  465           PRINTF(
"\n*** RELEASED HTTPD Session\n");
 
    A simple webserver for web services  
 
int etimer_expired(struct etimer *et)
Check if an event timer has expired. 
 
#define PT_WAIT_THREAD(pt, thread)
Block and wait until a child protothread completes. 
 
Hostname is fresh and usable. 
 
#define PSOCK_READTO(psock, c)
Read data up to a specified character. 
 
#define PSOCK_CLOSE_EXIT(psock)
Close a protosocket and exit the protosocket's protothread. 
 
void timer_restart(struct timer *t)
Restart the timer from the current point in time. 
 
#define PROCESS_BEGIN()
Define the beginning of a process. 
 
#define PSOCK_BEGIN(psock)
Start the protosocket protothread in a function. 
 
Representation of a uIP TCP connection. 
 
CCIF struct uip_conn * tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Open a TCP connection to the specified IP address and port. 
 
#define uip_aborted()
Has the connection been aborted by the other end? 
 
void timer_set(struct timer *t, clock_time_t interval)
Set a timer. 
 
#define NULL
The null pointer. 
 
#define PT_INIT(pt)
Initialize a protothread. 
 
#define uip_poll()
Is the connection being polled by uIP? 
 
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order. 
 
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation. 
 
#define PT_THREAD(name_args)
Declaration of a protothread. 
 
#define uip_connected()
Has the connection just been connected? 
 
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true. 
 
#define PROCESS_THREAD(name, ev, data)
Define the body of a process. 
 
#define PROCESS_END()
Define the end of a process. 
 
#define uip_abort()
Abort the current connection. 
 
#define PSOCK_INIT(psock, buffer, buffersize)
Initialize a protosocket. 
 
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order. 
 
#define PSOCK_CLOSE(psock)
Close a protosocket. 
 
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition. 
 
#define PSOCK_END(psock)
Declare the end of a protosocket's protothread. 
 
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread. 
 
#define PSOCK_READBUF_LEN(psock, len)
Read data until at least len bytes have been read. 
 
#define PROCESS(name, strname)
Declare a process. 
 
#define uip_close()
Close the current connection. 
 
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set. 
 
process_event_t tcpip_event
The uIP event. 
 
#define uip_timedout()
Has the connection timed out? 
 
#define PT_END(pt)
Declare the end of a protothread. 
 
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer. 
 
CCIF void tcp_listen(uint16_t port)
Open a TCP port. 
 
#define PSOCK_DATALEN(psock)
The length of the data that was previously read. 
 
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process. 
 
#define uip_closed()
Has the connection been closed by the other end? 
 
int timer_expired(struct timer *t)
Check if a timer has expired. 
 
#define PT_EXIT(pt)
Exit the protothread. 
 
#define CLOCK_SECOND
A second, measured in system clock time. 
 
#define PROCESS_CONTEXT_END(p)
End a context switch.