Contiki 3.x
http-socket.c
1 /*
2  * Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 #include "contiki-net.h"
32 #include "ip64-addr.h"
33 #include "http-socket.h"
34 
35 #include <ctype.h>
36 #include <stdio.h>
37 
38 #define MAX_PATHLEN 80
39 #define MAX_HOSTLEN 40
40 PROCESS(http_socket_process, "HTTP socket process");
41 LIST(socketlist);
42 
43 static void removesocket(struct http_socket *s);
44 /*---------------------------------------------------------------------------*/
45 static void
46 call_callback(struct http_socket *s, http_socket_event_t e,
47  const uint8_t *data, uint16_t datalen)
48 {
49  if(s->callback != NULL) {
50  s->callback(s, s->callbackptr, e,
51  data, datalen);
52  }
53 }
54 /*---------------------------------------------------------------------------*/
55 static void
56 parse_header_init(struct http_socket *s)
57 {
58  PT_INIT(&s->headerpt);
59 }
60 /*---------------------------------------------------------------------------*/
61 static int
62 parse_header_byte(struct http_socket *s, char c)
63 {
64  PT_BEGIN(&s->headerpt);
65 
66  memset(&s->header, -1, sizeof(s->header));
67 
68  /* Skip the HTTP response */
69  while(c != ' ') {
70  PT_YIELD(&s->headerpt);
71  }
72 
73  /* Skip the space */
74  PT_YIELD(&s->headerpt);
75  /* Read three characters of HTTP status and convert to BCD */
76  s->header.status_code = 0;
77  for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) {
78  s->header.status_code = s->header.status_code << 4 | (c - '0');
79  PT_YIELD(&s->headerpt);
80  }
81 
82  if(s->header.status_code == 0x200 || s->header.status_code == 0x206) {
83  /* Read headers until data */
84 
85  while(1) {
86  /* Skip characters until end of line */
87  do {
88  while(c != '\r') {
89  s->header_chars++;
90  PT_YIELD(&s->headerpt);
91  }
92  s->header_chars++;
93  PT_YIELD(&s->headerpt);
94  } while(c != '\n');
95  s->header_chars--;
96  PT_YIELD(&s->headerpt);
97 
98  if(s->header_chars == 0) {
99  /* This was an empty line, i.e. the end of headers */
100  break;
101  }
102 
103  /* Start of line */
104  s->header_chars = 0;
105 
106  /* Read header field */
107  while(c != ' ' && c != '\t' && c != ':' && c != '\r' &&
108  s->header_chars < sizeof(s->header_field) - 1) {
109  s->header_field[s->header_chars++] = c;
110  PT_YIELD(&s->headerpt);
111  }
112  s->header_field[s->header_chars] = '\0';
113  /* Skip linear white spaces */
114  while(c == ' ' || c == '\t') {
115  s->header_chars++;
116  PT_YIELD(&s->headerpt);
117  }
118  if(c == ':') {
119  /* Skip the colon */
120  s->header_chars++;
121  PT_YIELD(&s->headerpt);
122  /* Skip linear white spaces */
123  while(c == ' ' || c == '\t') {
124  s->header_chars++;
125  PT_YIELD(&s->headerpt);
126  }
127  if(!strcmp(s->header_field, "Content-Length")) {
128  s->header.content_length = 0;
129  while(isdigit((int)c)) {
130  s->header.content_length = s->header.content_length * 10 + c - '0';
131  s->header_chars++;
132  PT_YIELD(&s->headerpt);
133  }
134  } else if(!strcmp(s->header_field, "Content-Range")) {
135  /* Skip the bytes-unit token */
136  while(c != ' ' && c != '\t') {
137  s->header_chars++;
138  PT_YIELD(&s->headerpt);
139  }
140  /* Skip linear white spaces */
141  while(c == ' ' || c == '\t') {
142  s->header_chars++;
143  PT_YIELD(&s->headerpt);
144  }
145  s->header.content_range.first_byte_pos = 0;
146  while(isdigit((int)c)) {
147  s->header.content_range.first_byte_pos =
148  s->header.content_range.first_byte_pos * 10 + c - '0';
149  s->header_chars++;
150  PT_YIELD(&s->headerpt);
151  }
152  /* Skip linear white spaces */
153  while(c == ' ' || c == '\t') {
154  s->header_chars++;
155  PT_YIELD(&s->headerpt);
156  }
157  if(c == '-') {
158  /* Skip the dash */
159  s->header_chars++;
160  PT_YIELD(&s->headerpt);
161  /* Skip linear white spaces */
162  while(c == ' ' || c == '\t') {
163  s->header_chars++;
164  PT_YIELD(&s->headerpt);
165  }
166  s->header.content_range.last_byte_pos = 0;
167  while(isdigit((int)c)) {
168  s->header.content_range.last_byte_pos =
169  s->header.content_range.last_byte_pos * 10 + c - '0';
170  s->header_chars++;
171  PT_YIELD(&s->headerpt);
172  }
173  /* Skip linear white spaces */
174  while(c == ' ' || c == '\t') {
175  s->header_chars++;
176  PT_YIELD(&s->headerpt);
177  }
178  if(c == '/') {
179  /* Skip the slash */
180  s->header_chars++;
181  PT_YIELD(&s->headerpt);
182  /* Skip linear white spaces */
183  while(c == ' ' || c == '\t') {
184  s->header_chars++;
185  PT_YIELD(&s->headerpt);
186  }
187  if(c != '*') {
188  s->header.content_range.instance_length = 0;
189  while(isdigit((int)c)) {
190  s->header.content_range.instance_length =
191  s->header.content_range.instance_length * 10 + c - '0';
192  s->header_chars++;
193  PT_YIELD(&s->headerpt);
194  }
195  }
196  }
197  }
198  }
199  }
200  }
201 
202  /* All headers read, now read data */
203  call_callback(s, HTTP_SOCKET_HEADER, (void *)&s->header, sizeof(s->header));
204 
205  /* Should exit the pt here to indicate that all headers have been
206  read */
207  PT_EXIT(&s->headerpt);
208  } else {
209  if(s->header.status_code == 0x404) {
210  printf("File not found\n");
211  } else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) {
212  printf("File moved (not handled)\n");
213  }
214 
215  call_callback(s, HTTP_SOCKET_ERR, (void *)&s->header, sizeof(s->header));
216  tcp_socket_close(&s->s);
217  removesocket(s);
218  PT_EXIT(&s->headerpt);
219  }
220 
221 
222  PT_END(&s->headerpt);
223 }
224 /*---------------------------------------------------------------------------*/
225 static int
226 input_pt(struct http_socket *s,
227  const uint8_t *inputptr, int inputdatalen)
228 {
229  int i;
230  PT_BEGIN(&s->pt);
231 
232  /* Parse the header */
233  s->header_received = 0;
234  do {
235  for(i = 0; i < inputdatalen; i++) {
236  if(!PT_SCHEDULE(parse_header_byte(s, inputptr[i]))) {
237  s->header_received = 1;
238  break;
239  }
240  }
241  inputdatalen -= i;
242  inputptr += i;
243 
244  if(s->header_received == 0) {
245  /* If we have not yet received the full header, we wait for the
246  next packet to arrive. */
247  PT_YIELD(&s->pt);
248  }
249  } while(s->header_received == 0);
250 
251  s->bodylen = 0;
252  do {
253  /* Receive the data */
254  call_callback(s, HTTP_SOCKET_DATA, inputptr, inputdatalen);
255 
256  /* Close the connection if the expected content length has been received */
257  if(s->header.content_length >= 0 && s->bodylen < s->header.content_length) {
258  s->bodylen += inputdatalen;
259  if(s->bodylen >= s->header.content_length) {
260  tcp_socket_close(&s->s);
261  }
262  }
263 
264  PT_YIELD(&s->pt);
265  } while(inputdatalen > 0);
266 
267  PT_END(&s->pt);
268 }
269 /*---------------------------------------------------------------------------*/
270 static void
271 start_timeout_timer(struct http_socket *s)
272 {
273  PROCESS_CONTEXT_BEGIN(&http_socket_process);
274  etimer_set(&s->timeout_timer, HTTP_SOCKET_TIMEOUT);
275  PROCESS_CONTEXT_END(&http_socket_process);
276  s->timeout_timer_started = 1;
277 }
278 /*---------------------------------------------------------------------------*/
279 static int
280 input(struct tcp_socket *tcps, void *ptr,
281  const uint8_t *inputptr, int inputdatalen)
282 {
283  struct http_socket *s = ptr;
284 
285  input_pt(s, inputptr, inputdatalen);
286  start_timeout_timer(s);
287 
288  return 0; /* all data consumed */
289 }
290 /*---------------------------------------------------------------------------*/
291 static int
292 parse_url(const char *url, char *host, uint16_t *portptr, char *path)
293 {
294  const char *urlptr;
295  int i;
296  const char *file;
297  uint16_t port;
298 
299  if(url == NULL) {
300  printf("null url\n");
301  return 0;
302  }
303 
304  /* Don't even try to go further if the URL is empty. */
305  if(strlen(url) == 0) {
306  printf("empty url\n");
307  return 0;
308  }
309 
310  /* See if the URL starts with http:// and remove it. Otherwise, we
311  assume it is an implicit http://. */
312  if(strncmp(url, "http://", strlen("http://")) == 0) {
313  urlptr = url + strlen("http://");
314  } else {
315  urlptr = url;
316  }
317 
318  /* Find host part of the URL. */
319  if(*urlptr == '[') {
320  /* Handle IPv6 addresses - scan for matching ']' */
321  urlptr++;
322  for(i = 0; i < MAX_HOSTLEN; ++i) {
323  if(*urlptr == ']') {
324  if(host != NULL) {
325  host[i] = 0;
326  }
327  urlptr++;
328  break;
329  }
330  if(host != NULL) {
331  host[i] = *urlptr;
332  }
333  ++urlptr;
334  }
335  } else {
336  for(i = 0; i < MAX_HOSTLEN; ++i) {
337  if(*urlptr == 0 ||
338  *urlptr == '/' ||
339  *urlptr == ' ' ||
340  *urlptr == ':') {
341  if(host != NULL) {
342  host[i] = 0;
343  }
344  break;
345  }
346  if(host != NULL) {
347  host[i] = *urlptr;
348  }
349  ++urlptr;
350  }
351  }
352 
353  /* check if host is null terminated */
354  if(!memchr(host, 0, MAX_HOSTLEN)) {
355  return 0;
356  }
357 
358  /* Find the port. Default is 80. */
359  port = 80;
360  if(*urlptr == ':') {
361  port = 0;
362  do {
363  ++urlptr;
364  if(*urlptr >= '0' && *urlptr <= '9') {
365  port = (10 * port) + (*urlptr - '0');
366  }
367  } while(*urlptr >= '0' &&
368  *urlptr <= '9');
369  }
370  if(portptr != NULL) {
371  *portptr = port;
372  }
373  /* Find file part of the URL. */
374  while(*urlptr != '/' && *urlptr != 0) {
375  ++urlptr;
376  }
377  if(*urlptr == '/') {
378  file = urlptr;
379  } else {
380  file = "/";
381  }
382  if(path != NULL) {
383  strncpy(path, file, MAX_PATHLEN);
384  }
385  return 1;
386 }
387 /*---------------------------------------------------------------------------*/
388 static void
389 removesocket(struct http_socket *s)
390 {
391  etimer_stop(&s->timeout_timer);
392  s->timeout_timer_started = 0;
393  list_remove(socketlist, s);
394 }
395 /*---------------------------------------------------------------------------*/
396 static void
397 event(struct tcp_socket *tcps, void *ptr,
398  tcp_socket_event_t e)
399 {
400  struct http_socket *s = ptr;
401  char host[MAX_HOSTLEN];
402  char path[MAX_PATHLEN];
403  uint16_t port;
404  char str[42];
405  int len;
406 
407  if(e == TCP_SOCKET_CONNECTED) {
408  printf("Connected\n");
409  if(parse_url(s->url, host, &port, path)) {
410  tcp_socket_send_str(tcps, s->postdata != NULL ? "POST " : "GET ");
411  if(s->proxy_port != 0) {
412  /* If we are configured to route through a proxy, we should
413  provide the full URL as the path. */
414  tcp_socket_send_str(tcps, s->url);
415  } else {
416  tcp_socket_send_str(tcps, path);
417  }
418  tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
419  tcp_socket_send_str(tcps, "Connection: close\r\n");
420  tcp_socket_send_str(tcps, "Host: ");
421  /* If we have IPv6 host, add the '[' and the ']' characters
422  to the host. As in rfc2732. */
423  if(memchr(host, ':', MAX_HOSTLEN)) {
424  tcp_socket_send_str(tcps, "[");
425  }
426  tcp_socket_send_str(tcps, host);
427  if(memchr(host, ':', MAX_HOSTLEN)) {
428  tcp_socket_send_str(tcps, "]");
429  }
430  tcp_socket_send_str(tcps, "\r\n");
431  if(s->postdata != NULL) {
432  if(s->content_type) {
433  tcp_socket_send_str(tcps, "Content-Type: ");
434  tcp_socket_send_str(tcps, s->content_type);
435  tcp_socket_send_str(tcps, "\r\n");
436  }
437  tcp_socket_send_str(tcps, "Content-Length: ");
438  sprintf(str, "%u", s->postdatalen);
439  tcp_socket_send_str(tcps, str);
440  tcp_socket_send_str(tcps, "\r\n");
441  } else if(s->length || s->pos > 0) {
442  tcp_socket_send_str(tcps, "Range: bytes=");
443  if(s->length) {
444  if(s->pos >= 0) {
445  sprintf(str, "%llu-%llu", s->pos, s->pos + s->length - 1);
446  } else {
447  sprintf(str, "-%llu", s->length);
448  }
449  } else {
450  sprintf(str, "%llu-", s->pos);
451  }
452  tcp_socket_send_str(tcps, str);
453  tcp_socket_send_str(tcps, "\r\n");
454  }
455  tcp_socket_send_str(tcps, "\r\n");
456  if(s->postdata != NULL && s->postdatalen) {
457  len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
458  s->postdata += len;
459  s->postdatalen -= len;
460  }
461  }
462  parse_header_init(s);
463  } else if(e == TCP_SOCKET_CLOSED) {
464  call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0);
465  removesocket(s);
466  printf("Closed\n");
467  } else if(e == TCP_SOCKET_TIMEDOUT) {
468  call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0);
469  removesocket(s);
470  printf("Timedout\n");
471  } else if(e == TCP_SOCKET_ABORTED) {
472  call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0);
473  removesocket(s);
474  printf("Aborted\n");
475  } else if(e == TCP_SOCKET_DATA_SENT) {
476  if(s->postdata != NULL && s->postdatalen) {
477  len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
478  s->postdata += len;
479  s->postdatalen -= len;
480  } else {
481  start_timeout_timer(s);
482  }
483  }
484 }
485 /*---------------------------------------------------------------------------*/
486 static int
487 start_request(struct http_socket *s)
488 {
489  uip_ip4addr_t ip4addr;
490  uip_ip6addr_t ip6addr;
491  uip_ip6addr_t *addr;
492  char host[MAX_HOSTLEN];
493  char path[MAX_PATHLEN];
494  uint16_t port;
495  int ret;
496 
497  if(parse_url(s->url, host, &port, path)) {
498 
499  printf("url %s host %s port %d path %s\n",
500  s->url, host, port, path);
501 
502  /* Check if we are to route the request through a proxy. */
503  if(s->proxy_port != 0) {
504  /* The proxy address should be an IPv6 address. */
505  uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
506  port = s->proxy_port;
507  } else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
508  /* First check if the host is an IP address. */
509  if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
510  ip64_addr_4to6(&ip4addr, &ip6addr);
511  } else {
512  /* Try to lookup the hostname. If it fails, we initiate a hostname
513  lookup. */
514  ret = resolv_lookup(host, &addr);
515  if(ret == RESOLV_STATUS_UNCACHED ||
516  ret == RESOLV_STATUS_EXPIRED) {
517  resolv_query(host);
518  puts("Resolving host...");
519  return HTTP_SOCKET_OK;
520  }
521  if(addr != NULL) {
522  s->did_tcp_connect = 1;
523  tcp_socket_connect(&s->s, addr, port);
524  return HTTP_SOCKET_OK;
525  } else {
526  return HTTP_SOCKET_ERR;
527  }
528  }
529  }
530  tcp_socket_connect(&s->s, &ip6addr, port);
531  return HTTP_SOCKET_OK;
532  } else {
533  return HTTP_SOCKET_ERR;
534  }
535 }
536 /*---------------------------------------------------------------------------*/
537 PROCESS_THREAD(http_socket_process, ev, data)
538 {
539  PROCESS_BEGIN();
540 
541  while(1) {
542 
544 
545  if(ev == resolv_event_found && data != NULL) {
546  struct http_socket *s;
547  const char *name = data;
548  /* Either found a hostname, or not. We need to go through the
549  list of http sockets and figure out to which connection this
550  reply corresponds, then either restart the HTTP get, or kill
551  it (if no hostname was found). */
552  for(s = list_head(socketlist);
553  s != NULL;
554  s = list_item_next(s)) {
555  char host[MAX_HOSTLEN];
556  if(s->did_tcp_connect) {
557  /* We already connected, ignored */
558  } else if(parse_url(s->url, host, NULL, NULL) &&
559  strcmp(name, host) == 0) {
560  if(resolv_lookup(name, NULL) == RESOLV_STATUS_CACHED) {
561  /* Hostname found, restart get. */
562  start_request(s);
563  } else {
564  /* Hostname not found, kill connection. */
565  call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
566  removesocket(s);
567  }
568  }
569  }
570  } else if(ev == PROCESS_EVENT_TIMER) {
571  struct http_socket *s;
572  struct etimer *timeout_timer = data;
573  /*
574  * A socket time-out has occurred. We need to go through the list of HTTP
575  * sockets and figure out to which socket this timer event corresponds,
576  * then close this socket.
577  */
578  for(s = list_head(socketlist);
579  s != NULL;
580  s = list_item_next(s)) {
581  if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
582  tcp_socket_close(&s->s);
583  break;
584  }
585  }
586  }
587  }
588 
589  PROCESS_END();
590 }
591 /*---------------------------------------------------------------------------*/
592 static void
593 init(void)
594 {
595  static uint8_t inited = 0;
596  if(inited == 0) {
597  process_start(&http_socket_process, NULL);
598  list_init(socketlist);
599  inited = 1;
600  }
601 }
602 /*---------------------------------------------------------------------------*/
603 void
604 http_socket_init(struct http_socket *s)
605 {
606  init();
607  uip_create_unspecified(&s->proxy_addr);
608  s->proxy_port = 0;
609 }
610 /*---------------------------------------------------------------------------*/
611 static void
612 initialize_socket(struct http_socket *s)
613 {
614  s->pos = 0;
615  s->length = 0;
616  s->postdata = NULL;
617  s->postdatalen = 0;
618  s->timeout_timer_started = 0;
619  PT_INIT(&s->pt);
620  tcp_socket_register(&s->s, s,
621  s->inputbuf, sizeof(s->inputbuf),
622  s->outputbuf, sizeof(s->outputbuf),
623  input, event);
624 }
625 /*---------------------------------------------------------------------------*/
626 int
627 http_socket_get(struct http_socket *s,
628  const char *url,
629  int64_t pos,
630  uint64_t length,
631  http_socket_callback_t callback,
632  void *callbackptr)
633 {
634  initialize_socket(s);
635  strncpy(s->url, url, sizeof(s->url));
636  s->pos = pos;
637  s->length = length;
638  s->callback = callback;
639  s->callbackptr = callbackptr;
640 
641  s->did_tcp_connect = 0;
642 
643  list_add(socketlist, s);
644 
645  return start_request(s);
646 }
647 /*---------------------------------------------------------------------------*/
648 int
649 http_socket_post(struct http_socket *s,
650  const char *url,
651  const void *postdata,
652  uint16_t postdatalen,
653  const char *content_type,
654  http_socket_callback_t callback,
655  void *callbackptr)
656 {
657  initialize_socket(s);
658  strncpy(s->url, url, sizeof(s->url));
659  s->postdata = postdata;
660  s->postdatalen = postdatalen;
661  s->content_type = content_type;
662 
663  s->callback = callback;
664  s->callbackptr = callbackptr;
665 
666  s->did_tcp_connect = 0;
667 
668  list_add(socketlist, s);
669 
670  return start_request(s);
671 }
672 /*---------------------------------------------------------------------------*/
673 int
674 http_socket_close(struct http_socket *socket)
675 {
676  struct http_socket *s;
677  for(s = list_head(socketlist);
678  s != NULL;
679  s = list_item_next(s)) {
680  if(s == socket) {
681  tcp_socket_close(&s->s);
682  removesocket(s);
683  return 1;
684  }
685  }
686  return 0;
687 }
688 /*---------------------------------------------------------------------------*/
689 void
690 http_socket_set_proxy(struct http_socket *s,
691  const uip_ipaddr_t *addr, uint16_t port)
692 {
693  uip_ipaddr_copy(&s->proxy_addr, addr);
694  s->proxy_port = port;
695 }
696 /*---------------------------------------------------------------------------*/
Hostname was found, but it's status has expired.
Definition: resolv.h:71
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
#define PT_SCHEDULE(f)
Schedule a protothread.
Definition: pt.h:270
#define PT_INIT(pt)
Initialize a protothread.
Definition: pt.h:79
#define LIST(name)
Declare a linked list.
Definition: list.h:86
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
#define PROCESS_CONTEXT_END(p)
End a context switch.
Definition: process.h:440
#define uip_create_unspecified(a)
set IP address a to unspecified
Definition: uip.h:2024
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1503
#define PT_YIELD(pt)
Yield from the current protothread.
Definition: pt.h:289
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: etimer.h:76
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1027
process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
Definition: resolv.c:286
Hostname was not found in the cache.
Definition: resolv.h:66
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Definition: etimer.c:243
Representation of an IP address.
Definition: uip.h:95
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
#define PT_EXIT(pt)
Exit the protothread.
Definition: pt.h:245
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
Definition: process.h:426
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define NULL
The null pointer.
resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t **ipaddr)
Look up a hostname in the array of known hostnames.
Definition: resolv.c:1349
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
Hostname is fresh and usable.
Definition: resolv.h:63
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void resolv_query(const char *name)
Queues a name so that a question for the name will be sent out.
Definition: resolv.c:1270
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120