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